说明
SpringSecurity的权限校是基于SpringSecurity的安全认证的详解说明(附完整代码)
(https://blog.csdn.net/qq_51076413/article/details/129102660)的讲解,如果不了解SpringSecurity是怎么认证,请先看下【SpringSecurity的安全认证的详解说明(附完整代码)
】
基于SpringSecurity的安全认证的详解说明(附完整代码),继续讲解权限的校验
开启权限校验
@EnableGlobalMethodSecurity(prePostEnabled = true)
- 首先在
SecurityConfig
类上添加@EnableGlobalMethodSecurity(prePostEnabled = true)
注解- 表示开启方法的权限校验(默认是关闭的,这里要开启校验)
下面以继承WebSecurityConfigurerAdapter
类配置的方法已过时,可以使用后面的配置
/**
* @ApiNote: SpringSecurity配置信息
* @Author: 陌路
* @Date: 2023/2/18 12:14
* @Tool: Created by IntelliJ IDEA
*/
//@Configuration
// 开启方法权限校验,默认是关闭的,这里要开启校验
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 注入自定义的过滤器,在用户名和密码认证之前执行(UsernamePasswordAuthenticationFilter之前)
@Resource
private TokenAuthorityFilter tokenAuthorityFilter;
@Resource
private AuthenticationEntryPoint authenticationEntryPoint;
@Resource
private AccessDeniedHandler accessDeniedHandler;
/**
* @apiNote: 注入密码加密工具
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* @apiNote: 注入AuthenticationManager对象来实现登录逻辑管理
*/
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
/**
* @apiNote: 配置请求认证和拦截
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 关闭Security的CSRF功能防御
http.csrf().disable()
// 不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 配置接口权限,getUserList必须具备system:dept:index权限才允许访问,否则不允许访问
.mvcMatchers("/getUserList").hasAnyAuthority("system:dept:index")
// 允许所有用户访问登录路径:anonymous(匿名访问,即允许未登录时访问,登录时则不允许访问)
.antMatchers("/user/login").anonymous()//匿名访问(未登录未认证的)
// 除以上请求路径外,其他所有请求都必须经过认证才能访问成功
.anyRequest().authenticated();
// 添加自定义的请求过滤器(tokenAuthorityFilter)并定义在指定哪个过滤器(UsernamePasswordAuthenticationFilter)执行前执行
http.addFilterBefore(tokenAuthorityFilter, UsernamePasswordAuthenticationFilter.class);
// 添加自定义异常处理器
http.exceptionHandling()
// 认证失败处理
.authenticationEntryPoint(authenticationEntryPoint)
// 授权失败处理
.accessDeniedHandler(accessDeniedHandler);
// 允许跨域配置
http.cors();
}
// 测试密码的加密和密码的验证
public static void main(String[] args) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
// 加密后的密文,每次加密结果都不一样,因为加密时会生成随机盐值
String encode = passwordEncoder.encode("123456");
// 校验用户输入的密码和加密后的密码是否一样,一样返回true,否则返回false
boolean matches = passwordEncoder.matches("123456", encode);
System.out.println("encode = " + encode);
System.out.println("matches = " + matches);
}
}
上面的配置方式已过时,可以使用下面的配置
/**
* @ApiNote: SpringSecurity配置信息
* @Author: 陌路
* @Date: 2023/2/18 12:14
* @Tool: Created by IntelliJ IDEA
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
@Resource
private TokenAuthorityFilter tokenAuthorityFilter;
@Resource
private AuthenticationConfiguration authenticationConfiguration;
@Resource
private AuthenticationEntryPoint authenticationEntryPoint;
@Resource
private AccessDeniedHandler accessDeniedHandler;
/**
* @apiNote: 注入AuthenticationManager对象来实现登录逻辑管理
*/
@Bean
public AuthenticationManager authenticationManager() throws Exception {
AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
return authenticationManager;
}
/**
* @apiNote: 注入密码加密工具
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 配置接口权限,getUserList必须具备system:dept:index权限才允许访问,否则不允许访问
.mvcMatchers("/getUserList").hasAnyAuthority("system:dept:index")
// 允许所有用户访问登录路径:anonymous(匿名访问,即允许未登录时访问,登录时则不允许访问)
.antMatchers("/user/login").anonymous()
// 除以上请求路径外,其他所有请求都必须经过认证才能访问成功
.anyRequest().authenticated()
.and()
// 添加自定义的请求过滤器(tokenAuthorityFilter)并定义在指定哪个过滤器(UsernamePasswordAuthenticationFilter)执行前执行
.addFilterBefore(tokenAuthorityFilter, UsernamePasswordAuthenticationFilter.class);
// 添加异常处理器
http.exceptionHandling()
// 授权异常处理器
.accessDeniedHandler(accessDeniedHandler)
// 认证异常处理器
.authenticationEntryPoint(authenticationEntryPoint);
// 运行跨域配置
http.cors();
return http.build();
}
}
定义权限信息
/**
* @ApiNote: 菜单对象实体类,对应表(sys_menu)
* @Author: 陌路
* @Date: 2023/2/19 11:33
* @Tool: Created by IntelliJ IDEA
*/
@Data
@NoArgsConstructor
@TableName("sys_menu")
@ToString(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Menu implements Serializable {
private static final long serialVersionUID = -54979041104113736L;
@TableId
private Long id;
private String menuName;//菜单名
private String path;//路由地址
private String component;//组件路径
private String visible;//菜单状态(0显示 1隐藏)
private String status;//菜单状态(0正常 1停用)
private String perms;//权限标识
private String icon; //菜单图标
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;
private Integer delFlag;//是否删除(0未删除 1已删除)
private String remark;//备注
}
根据用户id获取权限信息
/**
* @ApiNote: 菜单权限$
* @Author: 陌路
* @Date: 2023/2/19 11:35
* @Tool: Created by IntelliJ IDEA
*/
@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
/**
* @apiNote: 根据用户id获取权限
* @param: userId
* @return: list
*/
List<String> queryPermsByUserId(Long userId);
}
根据用户id获取所拥有的权限信息
<select id="queryPermsByUserId" parameterType="long" resultType="string">
SELECT DISTINCT M.PERMS
FROM SYS_USER_ROLE U
LEFT JOIN SYS_ROLE R ON U.ROLE_ID = R.ID
LEFT JOIN SYS_ROLE_MENU RM ON U.ROLE_ID = RM.ROLE_ID
LEFT JOIN SYS_MENU M ON M.ID = RM.MENU_ID
WHERE USER_ID = #{userId}
AND R.STATUS = 0
AND M.STATUS = 0
</select>
- 用户登录成功时,根据当前用户信息获取该用户所拥有的的权限,并将权限封装到
LoginUser
中- 在
LoginUser
中再将权限信息通过SpringSecurity
提供的方法(getAuthorities
)配置到SpringSecurity
管理中menuMapper.queryPermsByUserId(user.getId());
根据用户id获取所拥有的权限
配置文件配置MyBatis-Plus的信息
spring:
# 数据库链接配置
datasource:
url: jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
application:
name: SpringSecurity-JWT
# 热部署
devtools:
restart:
enabled: true
additional-paths: src/main/java
# 服务端口
server:
port: 8090
# token有效期为5分钟
token:
expire: 300000
# 用于生成JWT的盐值
jwt:
secret: 1234567890
# xml文件路径地址
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
/**
* @ApiNote: 用户数据认证
* @Author: 陌路
* @Date: 2023/2/18 11:34
* @Tool: Created by IntelliJ IDEA
*/
@Service("userDetailsImpl")
public class UserDetailsImpl implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Resource
private MenuMapper menuMapper;
/**
* @apiNote: 根据用户名获取用户数据
* @param: username 用户名
* @return: UserDetails
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户名查询用户数据
User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserName, username));
ApiUtils.checkParamsIsEmpty("未获取到用户数据,请检查用户名和密码是否正确!", user);
// 根据用户信息查询相关权限
List<String> list = menuMapper.queryPermsByUserId(user.getId());
// 将用户数据和用户权限数据封装到LoginUser中并返回
return new LoginUser(user, list);
}
}
将权限封装到LoginUser
中
将权限信息封装到
LoginUser
中
private List<String> permissions;
// 用户权限信息private List<GrantedAuthority> authorityList;
//全部权限信息对象集合public Collection<? extends GrantedAuthority> getAuthorities() {...}
//封装成SpringSecurity
需要的格式public LoginUser(User user, List<String> permissions) {...}
// 提供有参构造
/**
* @ApiNote: 封装登录用户数据
* @Author: 陌路
* @Date: 2023/2/18 11:55
* @Tool: Created by IntelliJ IDEA
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class LoginUser implements UserDetails {
// 实现SpringSecurity提供的UserDetails接口来管理用户数据
private User user;
private Long expire; // 过期时间
private String token; // token
private List<String> permissions; // 用户权限信息
private List<GrantedAuthority> authorityList;
/**
* @apiNote: 获取当前登录用户信息
*/
public static LoginUser getLoginUser() {
LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return ApiUtils.getObj(loginUser, new LoginUser());
}
public LoginUser(User user, List<String> permissions) {
this.user = user;
this.permissions = permissions;
}
/**
* @apiNote: 用户权限信息
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 把permissions中的String权限封装到SimpleGrantedAuthority对象中(GrantedAuthority的实现类)
if (ObjUtil.isEmpty(this.authorityList)) {
this.authorityList = this.permissions
.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
return this.authorityList;
}
/**
* @apiNote: 获取用户密码
*/
@Override
public String getPassword() {
return user.getPassword();
}
/**
* @apiNote: 获取用户名
*/
@Override
public String getUsername() {
return user.getUserName();
}
/**
* @apiNote: 是否未过期(true : 未过期 , false : 已过期)
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* @apiNote: 是否锁定
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* @apiNote: 是否超时(true : 未超时 , false : 已超时)
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* @apiNote: 当前用户是否可用(true:可用,false:不可用)
*/
@Override
public boolean isEnabled() {
return true;
}
}
权限校验配置
- 在自定义的请求过滤器中,配置封装好的权限信息即可
new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
// 传入封装好了的权限信息
/**
* @ApiNote: 请求过滤器:是否认证是否有权访问
* @Author: 陌路
* @Date: 2023/2/18 13:04
* @Tool: Created by IntelliJ IDEA
*/
@Component
public class TokenAuthorityFilter extends OncePerRequestFilter {
@Resource
private TokenUtils tokenUtils;
@Resource
private ContextLoader contextLoader;
/**
* @apiNote: 请求过滤器
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取token数据
String authorityToken = ApiUtils.getStr(request.getHeader("Authorization"), request.getParameter("Authorization"));
// token为空直接放行
if (StringUtils.isBlank(authorityToken)) {
filterChain.doFilter(request, response);
return;
}
// 解析token数据得到userId
String userId = tokenUtils.getUserId(authorityToken);
// 从缓存中获取用户信息
LoginUser loginUser = contextLoader.getCacheUser(userId + "_TOKEN_" + authorityToken);
ApiUtils.checkParamsIsEmpty("请求失败,认证已过期!", loginUser, loginUser.getUser());
// 将用户信息封装到SecurityContextHolder中
//principal:用户数据,credentials:,authenticated:权限信息(loginUser.getAuthorities())
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}
使用权限校验规则
- 接口校验:在请求接口方法上添加
@PreAuthorize("hasAnyAuthority('system:dept:index')")
即可- 使用
SpringSecurity
默认配置校验规则
/**
* @ApiNote: 请求接口控制器
* @Author: 陌路
* @Date: 2023/2/18 9:53
* @Tool: Created by IntelliJ IDEA
*/
@RestController
@RequestMapping("/user/*")
public class IndexController {
@Resource
private UserService userService;
/**
* @apiNote: 获取用户列表
* @return: Result
*/
@GetMapping("getUserList")
@PreAuthorize("hasAnyAuthority('system:dept:index')") // SpringSecurity校验配置
// @PreAuthorize("@api.hasAuthority('system:dept:index')") // 自定义校验配置
public Result getUserList() {
return Result.ok(userService.queryList());
}
/**
* @apiNote: 用户登录接口
* @param: User对象实体
* @return: Result
*/
@PostMapping("login")
public Result login(@RequestBody User user) {
return userService.login(user);
}
/**
* @apiNote: 用户退出登录
* @return: Result
*/
@GetMapping("logout")
public Result logout() {
return Result.res(userService.logout());
}
}
SpringSecurity异常处理
- 认证失败: 实现
SpringSecurity
提供的AuthenticationEntryPoint
接口中的commence
方法来处理认证失败后的业务- 统一处理:统一返回JSON异常提示信息
- 在SpringSecurity配置类(
SecurityConfiguration
)中添加http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
即可
/**
* @ApiNote: 认证失败处理类
* @Author: 陌路
* @Date: 2023/2/19 12:25
* @Tool: Created by IntelliJ IDEA
*/
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
/**
* @apiNote: 认证失败处理
* @return: JSON(认证失败,请重新登录)
*/
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String authExceptionMessage = authException.getMessage();
authExceptionMessage = StringUtils.isBlank(ApiUtils.getStr(authExceptionMessage)) ? "认证失败,请重新登录!" : authExceptionMessage;
String jsonStr = JSONUtil.toJsonStr(Result.err(HttpStatus.UNAUTHORIZED.value(), authExceptionMessage));
ApiUtils.printJsonMsg(jsonStr, response);
}
}
授权异常统一处理
- 授权失败:实现
SpringSecurity
提供的AccessDeniedHandler
接口中的handle
方法来处理授权失败业务- 统一处理:统一返回JSON异常提示信息
- 在SpringSecurity配置类(
SecurityConfiguration
)中添加http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
即可
/**
* @ApiNote: 授权失败处理类
* @Author: 陌路
* @Date: 2023/2/19 12:53
* @Tool: Created by IntelliJ IDEA
*/
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
/**
* @apiNote: 授权失败处理
* @return: JSON(您的权限不足,无法访问资源!)
*/
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
String accessDeniedExceptionMessage = accessDeniedException.getMessage();
accessDeniedExceptionMessage = StringUtils.isBlank(ApiUtils.getStr(accessDeniedExceptionMessage)) ? "不允许访问" : accessDeniedExceptionMessage;
accessDeniedExceptionMessage = accessDeniedExceptionMessage.equals("不允许访问") ? "您的权限不足,无法访问资源!" : accessDeniedExceptionMessage;
String jsonStr = JSONUtil.toJsonStr(Result.err(HttpStatus.FORBIDDEN.value(), accessDeniedExceptionMessage));
ApiUtils.printJsonMsg(jsonStr, response);
}
}
配置自定义校验规则
- 需要自定义配置权限校验规则的可以按照
SpringSecurity
中的hasAuthority.()..
方法自定义- 注意点:定义Bean的时候
@Component("api")
中一定要添加上值,调用时需要根据@Component
中的值来调用当前的校验规则
/**
* @ApiNote: 自定义权限校验配置$
* @Author: 陌路
* @Date: 2023/2/19 14:25
* @Tool: Created by IntelliJ IDEA
*/
@Component("api")
public class ApiExpressionRoot {
/**
* @apiNote: 定义权限校验规则
* @param: authority:接口方法中的权限码
* @return: true:有权限允许方法。false:无权限不允许访问
*/
public final boolean hasAuthority(String authority) {
// 获取权限信息列表(TokenAuthorityFilter)已经将数据存到到LoginUser,直接调用即可
List<String> permissions = LoginUser.getLoginUser().getPermissions();
if (ObjUtil.isNotEmpty(permissions)) {
Set<String> set = new HashSet<>(permissions);
// 判断用户权限中是否包含此权限代码
return set.contains(authority);
}
return false;
}
}
自定义校验规则的使用
- 直接在请求接口方法上添加上自定义校验规则方法即可
- 注意:调用时需要使用SPEL表达式调用,否则不会生效
- 使用
@PreAuthorize("@api.hasAuthority('system:dept:index')")
其中@api
是自定义配置类ApiExpressionRoot
中定义的@Component("api")
,这时自定义规则就会生效了
/**
* @apiNote: 获取用户列表
* @return: Result
*/
@GetMapping("getUserList")
//@PreAuthorize("hasAnyAuthority('system:dept:index')") // SpringSecurity校验配置
@PreAuthorize("@api.hasAuthority('system:dept:index')") // 自定义校验配置
public Result getUserList() {
return Result.ok(userService.queryList());
}
调用成功
用到的SQL语句脚本
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`menu_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT '菜单名',
`path` varchar(200) DEFAULT NULL COMMENT '路由地址',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
`visible` char(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)',
`status` char(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
`perms` varchar(100) DEFAULT NULL COMMENT '权限标识',
`icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
`create_by` bigint NULL DEFAULT NULL,
`create_time` datetime NULL DEFAULT NULL,
`update_by` bigint NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
`del_flag` int NULL DEFAULT 0 COMMENT '是否删除(0未删除 1已删除)',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '菜单表';
-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (2, '部门管理', 'dept', 'system/dept/index', '0', '0', 'system:dept:index', '#', NULL, NULL, NULL, NULL, 0, NULL);
INSERT INTO `sys_menu` VALUES (3, '测试', 'test', 'system/test/index', '0', '0', 'system:test:index', '#', NULL, NULL, NULL, NULL, 0, NULL);
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
`role_key` varchar(100) DEFAULT NULL COMMENT '角色权限字符串',
`status` char(1) DEFAULT '0' COMMENT '角色状态(0正常 1停用)',
`del_flag` int NULL DEFAULT 0 COMMENT 'del_flag',
`create_by` bigint NULL DEFAULT NULL,
`create_time` datetime NULL DEFAULT NULL,
`update_by` bigint NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COMMENT = '角色表';
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (3, 'CEO', 'ceo', '0', 0, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `sys_role` VALUES (4, 'Coder', 'coder', '0', 0, NULL, NULL, NULL, NULL, NULL);
-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (
`role_id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`menu_id` bigint NOT NULL DEFAULT 0 COMMENT '菜单id',
PRIMARY KEY (`role_id`, `menu_id`) USING BTREE,
INDEX `menu_id`(`menu_id`) USING BTREE
-- CONSTRAINT `menu_id` FOREIGN KEY (`menu_id`) REFERENCES `sys_menu` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
-- CONSTRAINT `role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4;
-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES (3, 2);
INSERT INTO `sys_role_menu` VALUES (3, 3);
INSERT INTO `sys_role_menu` VALUES (4, 3);
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_name` varchar(64) DEFAULT 'NULL' COMMENT '用户名',
`nick_name` varchar(64) DEFAULT 'NULL' COMMENT '昵称',
`password` varchar(64) DEFAULT 'NULL' COMMENT '密码',
`status` char(1) DEFAULT '0' COMMENT '账号状态(0正常 1停用)',
`email` varchar(64) DEFAULT NULL COMMENT '邮箱',
`phonenumber` varchar(32) DEFAULT NULL COMMENT '手机号',
`sex` char(1) DEFAULT NULL COMMENT '用户性别(0男,1女,2未知)',
`avatar` varchar(128) DEFAULT NULL COMMENT '头像',
`user_type` char(1) DEFAULT '1' COMMENT '用户类型(0管理员,1普通用户)',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建人的用户id',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`del_flag` int NULL DEFAULT 0 COMMENT '删除标志(0代表未删除,1代表已删除)',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '用户表';
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (3, 'molu', 'molu', '$2a$10$1s.BtZ6Ay/nU7VB/cgaTv.PiYezHYWOLntRsUqFgter/hsMDViZ0K', '0', NULL, NULL, NULL, NULL, '1', NULL, NULL, NULL, NULL, 0);
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
`role_id` bigint NOT NULL DEFAULT 0 COMMENT '角色id',
PRIMARY KEY (`user_id`, `role_id`) USING BTREE,
INDEX `rold_id`(`role_id`) USING BTREE
-- CONSTRAINT `rold_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
-- CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (3, 3);
SET FOREIGN_KEY_CHECKS = 1;