登陆认证权限控制(2)—— 基于Spring security 安全框架的权限管理 注解式权限控制 RABC模型

news2024/11/25 15:49:28

在这里插入图片描述

前言

登陆认证,权限控制是一个系统必不可少的部分,一个开放访问的系统能否在上线后稳定持续运行其实很大程度上取决于登陆认证和权限控制措施是否到位,不然可能系统刚刚上线就会夭折。

Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。

本篇博客介绍Spring Security的使用,结合MySQL,Redis实现基于JWT的注解式的权限认证,并且可以实现给不同的用户显示不同的前端页面。

代码仓库:https://gitee.com/pet365/spring-security-demo

在这里插入图片描述

其他相关的权限文章如下:

  • 从http请求 到 cookie 到 session & 用 session控制 删改数据的权限

  • 使用token的权限验证方法 & 用户+角色+权限表设计 & SpringBoot项目应用

  • 登陆认证&权限控制(1)——从session到token认证的变迁 & session的问题分析 + CSRF攻击的认识

文章目录

  • 前言
  • 引出
  • 初识spring security安全框架
    • 快速入门
  • spring security的项目应用
    • 安全框架的配置
    • UserDetailsService接口
      • 1、基本概念
      • 2、UserDetailsService获取用户名,密码,权限
      • 3、UserInfo extends User
    • 设置拦截器handler
      • 1、登录成功的拦截器
      • 2、请求访问通过OncePerRequestFilter过滤器
  • 权限相关表设计
    • RBAC基于角色的访问控制
    • 数据库表设计
    • 查询语句
    • 权限的注解式控制
      • 配置打开注解
      • 使用注解控制权限
    • 给不同的用户显示不同的页面
      • 数据库表设计
      • 查询语句
      • 不同用户显示的效果
  • 总结
    • 附录:
      • 1、前端页面
      • 2、MySQL数据库语句

引出


1.Spring Security的使用,结合MySQL,Redis实现基于JWT的注解式的权限认证,并且可以实现给不同的用户显示不同的前端页面;
2.项目中的快速应用和使用,拦截器的设置,安全框架的配置;
3.权限表的设计,基于角色的访问控制RABC模型;
4.启动注解的配置,通过注解实现权限的控制;
5.给不同的用户显示不同的页面,相关的SQL以及前端页面;

初识spring security安全框架

Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC(Inversion of Control 控制反转),DI(Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

Spring Security 拥有以下特性:

  • 对身份验证和授权的全面且可扩展的支持
  • 防御会话固定、点击劫持,跨站请求伪造等攻击
  • 支持 Servlet API 集成
  • 支持与 Spring Web MVC 集成

Spring、Spring Boot 和 Spring Security 三者的关系如下图所示:

在这里插入图片描述

快速入门

1、引入依赖

<!--springboot整合security坐标-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2、创建一个控制器

@RestController
public class HelloController {
    @GetMapping("hello")
    public String hello(){
        return "Hello Spring security";
    }
}

3、启动项目

访问:http://localhost:8080/hello 结果打开的是一个登录页面,其实这时候我们的请求已经被保护起来了,要想访问,需要先登录。

在这里插入图片描述

Spring Security 默认提供了一个用户名为 user 的用户,其密码在控制台可以找到

spring security的项目应用

安全框架的配置

在这里插入图片描述

Spring Security 内置的 Password Encoder 有:

加密算法名称PasswordEncoder
NOOPNoOpPasswordEncoder.getInstance()
SHA256new StandardPasswordEncoder()
BCRYPT(官方推荐)new BCryptPasswordEncoder()
LDAPnew LdapShaPasswordEncoder()
PBKDF2new Pbkdf2PasswordEncoder()
SCRYPTnew SCryptPasswordEncoder()
MD4new Md4PasswordEncoder()
MD5new MessageDigestPasswordEncoder(“MD5”)
SHA_1new MessageDigestPasswordEncoder(“SHA-1”)
SHA_256new MessageDigestPasswordEncoder(“SHA-256”)

上述 Password Encoder 中有一个『无意义』的加密器:NoOpPasswordEncoder 。它对原始密码没有做任何处理(现在也被标记为废弃)。

记得使用 @SuppressWarnings(“deprecation”) 去掉 IDE 的警告信息。

package com.tianju.config;

import com.tianju.config.security.handler.*;
import com.tianju.config.security.service.MyUserDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * 框架中自定义用户名和密码
 */

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true) // 开启注解式权限控制
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private MyUserDetail myUserDetail;

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private JwtHandler jwtHandler;

    @Value("${security.isOpen}")
    private Boolean isOpen;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         * security硬性要求密码必须是密文
         */
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        // 对明文加密
//        String encode = passwordEncoder.encode("123");
//        System.out.println("加密后为:"+encode);
//        auth.inMemoryAuthentication().withUser("pet").password(encode).roles("admin");
        auth.userDetailsService(myUserDetail);
    }

    /**
     * 自定义表单,前端的页面
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        if (isOpen){
            hasSecurity(http);
        }else {
            noSecurity(http);
        }
    }

    /**
     * 不加安全框架,放行所有请求
     * @param http
     */
    private void noSecurity(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().permitAll()
                .and()
                .csrf().disable();
    }


    private void hasSecurity(HttpSecurity http) throws Exception {
        // 自定义页面
        http.formLogin()  // 需要自定义表单
                .loginPage("/login.html") // 自己登陆页面
                .loginProcessingUrl("/api/user/login") // 登陆请求地址
                .successHandler(loginSuccessHandler) // 给前端返回json字符串
                .failureHandler(new LoginFailHandler()) // 登陆失败给前端的字符串Json
                .permitAll() // 对上面两个进行放行
        ;

        http.exceptionHandling()
                .accessDeniedHandler(new NoAuthorityHandler()) // 登陆后没有权限的返回字符串Json
                .authenticationEntryPoint(new NotLoginHandler()) // 未登录
        ;

        //给接口配置权限
        //1:注解的方式
        //2:编码的方式
        http.authorizeRequests()
                // 无需登陆
                .antMatchers("/find","/api/img/upload","/api/img/hi","/api/map/fastMatch",
                        "/api/myLogin/username","/api/ali/pay","/api/ali/notify").permitAll() // 无需登陆
                .anyRequest().authenticated(); // 所有请求都拦截

        // 指定目标过滤器,填自己的过滤器
        http.addFilterBefore(jwtHandler, UsernamePasswordAuthenticationFilter.class);

        // 前后端项目中装禁用掉session(改用jwt)
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // CSRF是指跨站请求伪造(Cross-site request forgery)
        // https://www.jianshu.com/p/5ac8deb775b0
        http.csrf().disable(); // 关闭csrf过滤器
    }


    /**
     * 加密的类必须放入IOC容器中
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

UserDetailsService接口

1、基本概念

  • AuthenticationManager

    它是 “表面上” 的做认证和鉴权比对工作的那个人,它是认证和鉴权比对工作的起点。

    ProvierderManager 是 AuthenticationManager 接口的具体实现。

在这里插入图片描述

在这里插入图片描述

  • AuthenticationProvider

    它是 “实际上” 的做认证和鉴权比对工作的那个人。从命名上很容易看出,Provider 受 ProviderManager 的管理,ProviderManager 调用 Provider 进行认证和鉴权的比对工作。

    我们最常用到 DaoAuthenticationProvider 是 AuthenticationProvider 接口的具体实现。

在这里插入图片描述

  • UserDetailsService

    虽然 AuthenticationProvider 负责进行用户名和密码的比对工作,但是它并不清楚用户名和密码的『标准答案』,而标准答案则是由 UserDetailsService 来提供。简单来说,UserDetailsService 负责提供标准答案 ,以供 AuthenticationProvider 使用。

在这里插入图片描述

  • UserDetails

    UserDetails 它是存放用户认证信息和权限信息的标准答案的 “容器” ,它也是 UserDetailService “应该” 返回的内容。

在这里插入图片描述

  • PasswordEncoder

    Spring Security 要求密码不能是明文,必须经过加密器加密。这样,AuthenticationProvider 在做比对时,就必须知道『当初』密码时使用哪种加密器加密的。所以,AuthenticationProvider 除了要向 UserDetailsService 『要』用户名密码的标准答案之外,它还需要知道配套的加密算法(加密器)是什么

在这里插入图片描述

2、UserDetailsService获取用户名,密码,权限

在这里插入图片描述

3、UserInfo extends User

在这里插入图片描述

package com.tianju.config.security.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

public class UserInfo extends User {
    private Integer userId; // 用户的id
    private String realName; // 真实姓名

    public UserInfo(String username, String password,
                    Collection<? extends GrantedAuthority> authorities, Integer userId, String realName) {
        super(username, password, authorities);
        this.userId = userId;
        this.realName = realName;
    }

    public Integer getUserId() {
        return userId;
    }

    public String getRealName() {
        return realName;
    }
}

设置拦截器handler

在这里插入图片描述

1、登录成功的拦截器

在这里插入图片描述

2、请求访问通过OncePerRequestFilter过滤器

  • 1:是否携带了jwt

  • 2:解密清求头jwt

    不能解开:放行(到下一个过滤器》

    能解开:走到下一步

  • 3:对比redis中的jwt

    不一样:放行(到下一个过滤器)

    一样:走到下一步

  • 4:给jwt续期

  • 5:让容器中放入一个凭证(登陆凭证)

package com.tianju.config.security.handler;

import com.tianju.config.security.service.MyUserDetail;
import com.tianju.util.JwtUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 1:是否携带了jwt
 * 2:解密清求头jwt
 *      不能解开:放行(到下一个过滤器》
 *      能解开:走到下一步
 * 3:对比redis中的jwt
 *      不一样:放行(到下一个过滤器)
 *      一样:走到下一步
 * 4:给jwt续期
 * 5:让容器中放入一个凭证(登陆凭证)
 */
@Component
@Slf4j
public class JwtHandler extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate<String,Object> stringRedisTemplate;
    @Autowired
    private MyUserDetail myUserDetail;

    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        //1.获取请求头中的前端jwt
        String jwt = request.getHeader("jwt");
        //2.判断能否获取到jwt
        if (jwt == null) {
            filterChain.doFilter(request, response);
            log.warn("未携带Jwt");
            return;
        }
        //3.判断能否解密jwt
        if (!JwtUtil.decode(jwt)) {
            filterChain.doFilter(request, response);
            log.warn("未能解密jwt");
            return;
        }
        //4.通过jwt获取用户信息,然后根据key获取redis中的jwt
        Map userInfo = JwtUtil.getUserInfo(jwt);
        Long userId = (Long) userInfo.get("userId");
        String redisJwt = (String) stringRedisTemplate.opsForValue().get("jwt" + userId.intValue());
        //5.核验两个jwt
        if (!jwt.equals(redisJwt)) {
            filterChain.doFilter(request, response);
            log.warn("redis里的和前端的不一致");
            return;
        }
        //6.给jwt续期
        stringRedisTemplate.opsForValue().set("jwt" + userId, jwt, 30, TimeUnit.DAYS);
        //7.往security容器中放登录凭证
        //实现步骤:获取security上下文类,往里面放一个凭证
        String username = (String) userInfo.get("username");
        UserDetails userDetails = myUserDetail.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken upa = new UsernamePasswordAuthenticationToken(userDetails.getUsername(),
                                                  userDetails.getPassword(),userDetails.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(upa);
        /**
         * 记得放行
         */
        filterChain.doFilter(request, response);
    }
}

权限相关表设计

RBAC基于角色的访问控制

RBAC(Role-Based Access Control,基于角色的访问控制)模型是一种广泛用于访问控制的安全模型。它基于角色的概念,将权限授权和访问管理组织起来。

在RBAC模型中,有以下几个核心概念:

  • 角色(Role):角色是一组权限的集合,代表了用户在系统中所扮演的角色或身份。用户可以被分配一个或多个角色。
  • 权限(Permission):权限是对系统资源的操作权限。例如,读取、写入、执行等。权限定义了用户或角色可以进行的操作。
  • 用户(User):用户是系统的最终使用者,他们可以被分配一个或多个角色。
  • 资源(Resource):资源是受到访问控制保护的对象,可以是系统中的数据、功能、服务等。

数据库表设计

在这里插入图片描述

查询语句

SELECT 
ut.id,
ut.username,
ut.realname,
ut.password,
art.role_name,
art.role_note,
at.auth_name,
at.auth_url

FROM auth_user_tab ut
LEFT JOIN auth_role_user_tab arut ON arut.user_id=ut.id
LEFT JOIN auth_role_tab art ON art.role_id=arut.role_id
LEFT JOIN auth_role_privs_tab arpt ON arpt.rp_role=arut.role_id
LEFT JOIN auth_tab at ON at.auth_id=arpt.rp_privs

权限的注解式控制

配置打开注解

Spring Security 支持三套注解:

注解类型注解
jsr250 注解@DenyAll、@PermitAll、@RolesAllowed
secured 注解@Secured
prePost 注解@PreAuthorize、@PostAuthorize

使用什么注解在@EnableGlobalMethodSecurity开启,默认是关闭的,例如

@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled  = true,securedEnabled=true) //开启jsr250和secured注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

实际开发中最常用的写法 使用 @PreAuthorize(“hasRole(‘admin’)”)

在这里插入图片描述

使用注解控制权限

在这里插入图片描述

package com.tianju.controller;

import com.baomidou.mybatisplus.extension.api.R;
import com.tianju.entity.GoodType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/good/type")
public class GoodTypeController {

    @GetMapping
    @PreAuthorize("hasAnyAuthority('/good/query')")
    public String get(Integer id){
        return "查询的方法:"+id;
    }

    @PostMapping
    @PreAuthorize("hasAnyAuthority('/good/add')")
    public String add(GoodType goodType){
        return "新增商品的方法:"+goodType;
    }

    @DeleteMapping
    @PreAuthorize("hasAnyAuthority('/good/del')")
    public String deleteById(Integer id){
        return "删除的方法:"+id;
    }

    @PutMapping
    @PreAuthorize("hasAnyAuthority('/good/update')")
    public String updateById(GoodType goodType){
        return "修改的方法:"+goodType;
    }

}

给不同的用户显示不同的页面

数据库表设计

在这里插入图片描述

查询语句

SELECT
		aut.username,
		t_menu.id,
		t_menu.name,
		t_menu.link,
		t_menu.parentid,
		t_menu.icon
FROM auth_user_tab AS aut
				 LEFT JOIN t_employee_menu ON aut.id = t_employee_menu.employeeId
				 LEFT JOIN t_menu ON t_employee_menu.menuId = t_menu.id

不同用户显示的效果

admin用户登录

在这里插入图片描述

peter用户登录

在这里插入图片描述


总结

1.Spring Security的使用,结合MySQL,Redis实现基于JWT的注解式的权限认证,并且可以实现给不同的用户显示不同的前端页面;
2.项目中的快速应用和使用,拦截器的设置,安全框架的配置;
3.权限表的设计,基于角色的访问控制RABC模型;
4.启动注解的配置,通过注解实现权限的控制;
5.给不同的用户显示不同的页面,相关的SQL以及前端页面;

附录:

1、前端页面

在这里插入图片描述

<template>
  <el-container style="height: 100%">
    <el-header style="background-color: rgb(249, 195, 195);">

    </el-header>
    <el-container>
      <el-aside width="200px" style="background-color: rgb(241, 241, 202);">
        <el-col width="200px">
          <el-menu
            router
            default-active="2"
            class="el-menu-vertical-demo">
            <el-submenu :index="menu.id+''" 
            v-for="menu in menuList" :key="menu.id+''">
              <template slot="title">
                <i :class="menu.icon"></i>
                <span>{{ menu.name }}</span>
              </template>
                  <el-menu-item :index="cmenu.link" 
                  v-for="cmenu in menu.childrenMenu" :key="cmenu.id+''">
                    {{ cmenu.name }}
                  </el-menu-item>
            </el-submenu>
          </el-menu>
      </el-col>

      </el-aside>
      <el-main style="background-color: rgb(182, 182, 231);">
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>

</template>

<script>
  export default{
    data() {
      return {

        // 定义一个数据,菜单从数据中循环出来table tr
        // 找出一级菜单和二级菜单循环体
        menuList:[
          {id:'1',name:'公共模块',icon:'el-icon-menu',
          childrenMenu:[
            {id:'2',name:'调查问卷',link:'/bookList'},
            {id:'3',name:'资料中心',link:'bcd'},
            {id:'4',name:'工资中心',link:'cde'},
          ]},
          {id:'5',name:'业务目标',icon:'el-icon-document',
          childrenMenu:[
            {id:'5',name:'短期目标',link:'def'},
            {id:'6',name:'长期目标',link:'efg'},
          ]},
        ]

      };
    },
    methods: {
      // 查询用户拥有菜单
      queryUserMenu(){
        console.log("findMenu")
        this.$axios.get('/api/menu')
        .then(response=>{
          let resp = response.data
          console.log(resp)
          if (resp.resultCode.code==20000) {
            this.menuList = resp.results

          }
        })
      },
    },
    created(){
      this.queryUserMenu()
    }
    

}
</script>

<style scoped>

</style>

2、MySQL数据库语句

/*
 Navicat Premium Data Transfer

 Source Server         : 127.0.0.1
 Source Server Type    : MySQL
 Source Server Version : 80022
 Source Host           : 127.0.0.1:3306
 Source Schema         : auth_pet

 Target Server Type    : MySQL
 Target Server Version : 80022
 File Encoding         : 65001

 Date: 06/11/2023 15:44:35
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for auth_role_privs_tab
-- ----------------------------
DROP TABLE IF EXISTS `auth_role_privs_tab`;
CREATE TABLE `auth_role_privs_tab`  (
  `rp_id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色权限的中间表relationship',
  `rp_role` bigint NULL DEFAULT NULL COMMENT '对应的是角色id',
  `rp_privs` bigint NULL DEFAULT NULL COMMENT '对应的权限id',
  `created` datetime NULL DEFAULT NULL,
  `updated` datetime NULL DEFAULT NULL,
  `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`rp_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of auth_role_privs_tab
-- ----------------------------
INSERT INTO `auth_role_privs_tab` VALUES (1, 1, 1, '2023-08-06 17:26:48', '2023-08-06 17:26:53', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (2, 1, 2, '2023-08-06 17:27:09', '2023-08-06 17:27:12', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (3, 1, 3, '2023-08-06 17:28:14', '2023-08-06 17:28:21', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (4, 1, 4, '2023-08-06 17:28:17', '2023-08-06 17:28:24', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (5, 1, 5, '2023-08-06 17:28:19', '2023-08-06 17:28:26', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (6, 1, 6, '2023-10-07 19:32:23', '2023-10-07 19:32:26', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (7, 1, 7, '2023-10-07 19:32:29', '2023-10-07 19:32:31', 'admin');
INSERT INTO `auth_role_privs_tab` VALUES (8, 2, 1, '2023-10-07 19:53:21', NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (9, 2, 2, '2023-10-07 19:53:25', NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (10, 2, 3, '2023-10-07 19:53:28', NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (11, 2, 4, '2023-10-07 19:53:30', NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (12, 5, 5, NULL, NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (13, 5, 6, NULL, NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (14, 5, 7, NULL, NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (15, 3, NULL, NULL, NULL, NULL);
INSERT INTO `auth_role_privs_tab` VALUES (16, 4, 1, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for auth_role_tab
-- ----------------------------
DROP TABLE IF EXISTS `auth_role_tab`;
CREATE TABLE `auth_role_tab`  (
  `role_id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色的id,角色表',
  `role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色的name',
  `role_note` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注一下',
  `state` int NULL DEFAULT NULL COMMENT '状态,0启用,1删除',
  `created` datetime NULL DEFAULT NULL,
  `updated` datetime NULL DEFAULT NULL,
  `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of auth_role_tab
-- ----------------------------
INSERT INTO `auth_role_tab` VALUES (1, '老板Boss', '全部权限', 0, '2023-08-06 17:24:43', '2023-08-06 17:24:46', 'admin');
INSERT INTO `auth_role_tab` VALUES (2, '商品管理员工', '商品相关', 0, '2023-08-06 17:25:03', '2023-08-06 17:25:05', 'admin');
INSERT INTO `auth_role_tab` VALUES (3, '未实名用户', '无任何权限', 0, '2023-08-06 17:25:38', '2023-08-06 17:25:41', 'admin');
INSERT INTO `auth_role_tab` VALUES (4, '普通用户', '商品查询', 0, '2023-10-07 19:49:34', '2023-10-07 19:49:37', 'admin');
INSERT INTO `auth_role_tab` VALUES (5, '人事部门员工', '人事相关', 0, '2023-10-07 19:49:40', '2023-10-07 19:49:41', 'admin');
INSERT INTO `auth_role_tab` VALUES (7, '老板Boss1', NULL, 0, '2023-11-05 22:27:04', '2023-11-05 22:44:52', 'admin');

-- ----------------------------
-- Table structure for auth_role_user_tab
-- ----------------------------
DROP TABLE IF EXISTS `auth_role_user_tab`;
CREATE TABLE `auth_role_user_tab`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '角色,用户关联表,用户可能有多个角色',
  `user_id` int NULL DEFAULT NULL COMMENT '用户表的主键id',
  `role_id` int NULL DEFAULT NULL COMMENT '角色表的主键id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of auth_role_user_tab
-- ----------------------------
INSERT INTO `auth_role_user_tab` VALUES (1, 1, 1);
INSERT INTO `auth_role_user_tab` VALUES (2, 2, 2);
INSERT INTO `auth_role_user_tab` VALUES (3, 3, 5);
INSERT INTO `auth_role_user_tab` VALUES (4, 4, 4);
INSERT INTO `auth_role_user_tab` VALUES (5, 5, 3);

-- ----------------------------
-- Table structure for auth_tab
-- ----------------------------
DROP TABLE IF EXISTS `auth_tab`;
CREATE TABLE `auth_tab`  (
  `auth_id` int NOT NULL AUTO_INCREMENT COMMENT '权限表的id',
  `auth_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限的名称',
  `auth_url` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限的url,安全框架用',
  PRIMARY KEY (`auth_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of auth_tab
-- ----------------------------
INSERT INTO `auth_tab` VALUES (1, '商品查询', '/good/query');
INSERT INTO `auth_tab` VALUES (2, '商品新增', '/good/add');
INSERT INTO `auth_tab` VALUES (3, '商品删除', '/good/del');
INSERT INTO `auth_tab` VALUES (4, '商品修改', '/good/update');
INSERT INTO `auth_tab` VALUES (5, '员工查询', '/emp/query');
INSERT INTO `auth_tab` VALUES (6, '员工新增', '/emp/add');
INSERT INTO `auth_tab` VALUES (7, '员工开除', '/emp/del');

-- ----------------------------
-- Table structure for auth_user_tab
-- ----------------------------
DROP TABLE IF EXISTS `auth_user_tab`;
CREATE TABLE `auth_user_tab`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `realname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '真实姓名',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `tel` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
  `gender` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
  `identity` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '身份证号',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
  `operator` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作人',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of auth_user_tab
-- ----------------------------
INSERT INTO `auth_user_tab` VALUES (1, 'admin', '超级管理', '123', '19800305334', '女', '433123456787', NULL, NULL, NULL);
INSERT INTO `auth_user_tab` VALUES (2, 'peter', '商品管理', '123', '18802229403', '男', '433123456788', NULL, NULL, NULL);
INSERT INTO `auth_user_tab` VALUES (3, 'shirley', '人事管理', '123', NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `auth_user_tab` VALUES (4, 'tom', '普通登陆用户', '123', NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `auth_user_tab` VALUES (5, 'test', '未实名认证', NULL, NULL, NULL, NULL, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for t_employee_menu
-- ----------------------------
DROP TABLE IF EXISTS `t_employee_menu`;
CREATE TABLE `t_employee_menu`  (
  `id_menu` int NOT NULL AUTO_INCREMENT,
  `employeeId` int NULL DEFAULT NULL COMMENT '员工id',
  `menuId` int NULL DEFAULT NULL COMMENT '菜单表id',
  PRIMARY KEY (`id_menu`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_employee_menu
-- ----------------------------
INSERT INTO `t_employee_menu` VALUES (1, 1, 1);
INSERT INTO `t_employee_menu` VALUES (2, 1, 2);
INSERT INTO `t_employee_menu` VALUES (3, 1, 3);
INSERT INTO `t_employee_menu` VALUES (4, 1, 4);
INSERT INTO `t_employee_menu` VALUES (5, 1, 5);
INSERT INTO `t_employee_menu` VALUES (6, 1, 6);
INSERT INTO `t_employee_menu` VALUES (7, 1, 7);
INSERT INTO `t_employee_menu` VALUES (9, 1, 9);
INSERT INTO `t_employee_menu` VALUES (10, 1, 10);
INSERT INTO `t_employee_menu` VALUES (11, 1, 11);
INSERT INTO `t_employee_menu` VALUES (12, 1, 12);
INSERT INTO `t_employee_menu` VALUES (13, 1, 13);
INSERT INTO `t_employee_menu` VALUES (14, 1, 14);
INSERT INTO `t_employee_menu` VALUES (15, 1, 15);
INSERT INTO `t_employee_menu` VALUES (16, 1, 16);
INSERT INTO `t_employee_menu` VALUES (17, 1, 17);
INSERT INTO `t_employee_menu` VALUES (18, 1, 18);
INSERT INTO `t_employee_menu` VALUES (19, 1, 19);
INSERT INTO `t_employee_menu` VALUES (20, 1, 20);
INSERT INTO `t_employee_menu` VALUES (21, 1, 21);
INSERT INTO `t_employee_menu` VALUES (22, 1, 22);
INSERT INTO `t_employee_menu` VALUES (23, 1, 23);
INSERT INTO `t_employee_menu` VALUES (24, 1, 24);
INSERT INTO `t_employee_menu` VALUES (25, 1, 25);
INSERT INTO `t_employee_menu` VALUES (27, 1, 27);
INSERT INTO `t_employee_menu` VALUES (29, 2, 1);
INSERT INTO `t_employee_menu` VALUES (30, 2, 2);

-- ----------------------------
-- Table structure for t_menu
-- ----------------------------
DROP TABLE IF EXISTS `t_menu`;
CREATE TABLE `t_menu`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '权限名称',
  `link` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '菜单链接',
  `parentid` int NULL DEFAULT NULL COMMENT '父级',
  `status` int NULL DEFAULT NULL COMMENT '1:正常 0:禁用',
  `percode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '权限编码',
  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '图标',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `FK_ParentID`(`parentid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_menu
-- ----------------------------
INSERT INTO `t_menu` VALUES (1, '系统管理', '', NULL, NULL, NULL, 'el-icon-location');
INSERT INTO `t_menu` VALUES (2, '商品类别', 'goodsType', 1, NULL, NULL, '');
INSERT INTO `t_menu` VALUES (3, '计量单位', 'unit', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (4, '仓库管理', 'warehouse', NULL, NULL, NULL, 'el-icon-s-data');
INSERT INTO `t_menu` VALUES (5, '原材料入库', 'rawMaterialList', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (6, '原材料领库', 'pickRawList', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (7, '订单管理', NULL, NULL, NULL, NULL, 'el-icon-s-tools');
INSERT INTO `t_menu` VALUES (9, '区域管理', 'district', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (10, '商品资料', 'goodsList', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (11, '供应商资料', 'supplier', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (12, '客户资料', 'customer', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (13, '仓库管理', 'warehouse', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (14, '部门管理', 'department', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (15, '员工管理', 'employee', 1, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (16, '成品入库', 'finishedPickRaw', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (17, '次品入库', 'defectiveGoodsIn', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (18, '成品发货', 'finishedGoodsOut', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (19, '次品发货', 'defectiveGoodsSend', 4, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (20, '财务管理', NULL, NULL, NULL, NULL, 'el-icon-s-data');
INSERT INTO `t_menu` VALUES (21, '应收款管理', 'income', 20, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (22, '应付款管理', 'expenses', 20, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (23, '数据统计', NULL, NULL, NULL, NULL, 'el-icon-s-data');
INSERT INTO `t_menu` VALUES (24, '仓库报表', 'storeStatistics', 23, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (25, '财务报表', 'financialStatistics', 23, NULL, NULL, NULL);
INSERT INTO `t_menu` VALUES (27, '订单查询', 'orderSearch', 7, NULL, NULL, NULL);

SET FOREIGN_KEY_CHECKS = 1;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1183036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue2 集成 - 超图 - SuperMap iClient3D for WebGL 及常用方法

1:下载SuperMap iClient3D for WebGL SuperMap iClient3D for WebGL产品包 打开资源目录如下 2:格式化项目中所用的依赖包 开发指南 从超图官网下载SuperMap iClient3D 11i (2023) SP1 for WebGL_CN.zip解压后,将Build目录下的SuperMap3D复制到项目中 \public\static…

iOS Crash 治理:淘宝VisionKitCore 问题修复

本文通过逆向系统&#xff0c;阅读汇编指令&#xff0c;逐步找到源码&#xff0c;定位到了 iOS 16.0.<iOS 16.2 WKWebView 的系统bug 。同时苹果已经在新版本修复了 Bug&#xff0c;对于巨大的存量用户&#xff0c;仍旧会造成日均 Crash pv 1200 uv 1000&#xff0c; 最终通…

SpringCloud——三个服务注册中心的异同点

首先我们说一下什么是CAP&#xff1a; C&#xff1a;Consistency(强一致性) A&#xff1a;Availability(高可用性) P&#xff1a;Partition tolerance(分区容错性) CAP关注的粒度是数据&#xff01; AP(Eureka) CP(Zookeeper/Consul)

【Database System Concept 7th】Chapter 24 Advanced Indexing Techniques 读书笔记

Chapter 24 Advanced Indexing Techniques 24.5 Hash Indices24.5.1 Static Hashing24.5.2 Dynamic Hashing24.5.2.1 Data Structure24.5.2.2 Queries and Updates 24.5 Hash Indices 24.5.1 Static Hashing 这一部分就不介绍了&#xff0c;在14.5中已经介绍过了。 24.5.2 D…

攻击者滥用日历服务作为 C2 基础设施

谷歌警告多个威胁参与者正在利用其日历服务作为命令和控制&#xff08;C2&#xff09;基础设施。 谷歌警告 称&#xff0c;多个威胁参与者共享一个名为“Google Calendar RAT”的公共概念验证&#xff08;PoC&#xff09;漏洞&#xff0c;该漏洞依赖日历服务来托管命令和控制&…

SpringCloud——消息驱动——Stream

1.什么是消息驱动 消息驱动就是屏蔽底层消息中间件的差异&#xff0c;降低切换成本&#xff0c;统一消息的编程模型。目前仅支持RabbitMQ、Kafka。 2.消息中间件有什么问题&#xff0c;stream靠什么实现&#xff1f; 如果我们项目用到了RabbitMQ和Kafka&#xff0c;由于这两个…

大数据毕业设计选题推荐-超级英雄运营数据监控平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

torch.cuda.is_available()=false的原因

1、检查是否为nvidia显卡&#xff1b; 2、检查GPU是否支持cuda; 3、命令行cmd输入nvidia-smi&#xff08;中间没有空格&#xff09;&#xff0c;查看显卡信息&#xff0c;cuda9.2版本只支持Driver Version>396.26&#xff1b;如果小于这个值&#xff0c;那么你就需要更新显…

NCV7721D2R2G一款完全保护的双半桥驱动器 专为汽车工业运动控制解决方案

NCV7721D2R2G是一款完全保护的双半桥驱动器&#xff0c;专为汽车和工业运动控制应用而设计。两个半桥驱动器具有独立控制。这允许高侧、低侧和H桥控制。H桥控制提供正向、反向、制动和高阻抗状态。驱动器通过逻辑电平输入进行控制。 特性&#xff1a; 1.睡眠模式下的超低静态电…

多测师肖sir___ddt讲解(辅助框架)

ddt数据驱动 1、ddt定义&#xff1a;全称data-driver tests &#xff0c;数据驱动测试&#xff0c;可以实现不同数据运行同一个测试用例。 ddt本质是一个装饰器&#xff0c;一组数据一个场景 主要核心&#xff1a;把业务逻辑装成关键字&#xff0c;在调用关键字 2、为什么要使…

EasyExcel 导出冻结指定行

导出的实体类 package org.jeecg.modules.eis.test;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.HorizontalAlignment;import…

C语言面试

数据类型&#xff08;基本内置类型&#xff09; char //字符数据类型 short //短整型 int //整型 long //长整型 long long //更长的整型 float //单精度浮点数 double //双精度浮点数 类型的基本归类 整形家族&#xff1a; …

redis笔记 三 redis持久化

文章目录 Redis持久化RDB持久化执行时机RDB原理小结 AOF持久化AOF原理AOF配置AOF文件重写 RDB与AOF对比 Redis持久化 redis持久化是为了解决redis宕机时丢失数据的问题&#xff0c;Redis有两种持久化方案&#xff1a; RDB持久化AOF持久化 RDB持久化 RDB全称Redis Database …

避免重复请求:接口重试机制最佳实践

避免重复请求是设计接口重试机制时的重要考量之一。在实际的系统开发中&#xff0c;网络通信、服务调用等操作可能会面临重试的情况&#xff0c;而重试请求如果不加以处理可能导致重复执行业务逻辑、产生重复数据或是对服务端造成压力&#xff0c;因此如何有效避免重复请求成为…

Spring Boot项目中通过 Jasypt 对属性文件中的账号密码进行加密

下面是在Spring Boot项目中对属性文件中的账号密码进行加密的完整步骤&#xff0c;以MySQL的用户名为root&#xff0c;密码为123321为例&#xff1a; 步骤1&#xff1a;引入Jasypt依赖 在项目的pom.xml文件中&#xff0c;添加Jasypt依赖&#xff1a; <dependency><…

easyConnect虚拟网卡未安装,导致连接失败(虚拟网卡安装失败)

前言 使用easyConnect&#xff0c;但是一直连接失败&#xff0c;看到提示错误 虚拟网卡未安装&#xff0c;请确保虚拟网卡安装成功 我的错误原因是因为我自己装过VM虚拟机&#xff0c;用过虚拟网卡然后产生的虚拟网卡冲突 解决方式 1.打开网络设置2.选择你的网络&#xff08…

chatgpt升级啦,训练数据时间更新到2023年4月,支持tools(升级functionCall),128k上下文

&#xff08;2023年11月7日&#xff09; gpt-4-1106-preview https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo 训练数据日期升级到2023年四月 上线文增加到128k 调用一次chatgpt接口&#xff0c;可以得到多次函数调用 import OpenAI from "openai"…

1-前端基本知识-HTML

1-前端基本知识-HTML 文章目录 1-前端基本知识-HTML总体概述什么是HTML&#xff1f;超文本标记语言 HTML基础结构文档声明根标签头部元素主体元素注释 HTML概念词汇&#xff1a;标签、属性、文本、元素HTML基本语法规则HTML常见标签标题标签段落标签换行标签列表标签超链接标签…

华为取消6000万订单影响在扩大,高通嘴硬强调不受影响

高通公布了2023年第三季度的业绩&#xff0c;业绩显示营收下滑24%&#xff0c;净利润下滑36%&#xff0c;不过高通强调预计今年四季度业绩将回升&#xff0c;意思是说华为取消订单带来的影响较小。 一、高通处境不利已延续4年时间 2019年美国对华为采取措施&#xff0c;众多中国…

go程序获取工作目录及可执行程序存放目录的方法-linux

简介 工作目录 通常就是指用户启动应用程序时&#xff0c;用户当时所在的文件夹的绝对路径。 如&#xff1a;root用户登录到linux系统后&#xff0c;一顿cd&#xff08;change directory&#xff09;后, 到了/tmp文件夹下。此时&#xff0c;用户要启动某个应用程序&#xff0…