基于RBAC权限模型的系统用户管理模块实现

基于Spring Boot的系统用户管理模块实现

简介

在现代企业级应用中,用户管理模块是系统的基础功能之一。它通常包括用户的增删改查、登录认证、权限管理等功能。本文将详细解析一个基于Spring Boot的系统用户管理模块的实现流程。该模块使用了MyBatis Plus作为ORM框架,结合Redis进行验证码的存储与验证,同时通过Sa-Token进行权限控制。

代码结构

项目的主要代码结构如下:

  • UserController.java: 用户管理的控制器,负责处理HTTP请求。
  • UserService.java: 用户管理的服务接口,定义了用户管理的核心业务逻辑。
  • UserServiceImpl.java: 用户管理服务的具体实现类。
  • SysUser.java: 系统用户实体类,对应数据库中的用户表。

功能实现解析

1. 用户登录与验证码生成

1.1 登录功能

UserServiceImpl类中,login方法负责处理用户登录请求。登录流程如下:

  1. 解码请求参数:从LoginVO中获取经过Base64编码的用户名、密码、验证码和验证码Token,并进行解码。

    String username = new String(Base64.getDecoder().decode(loginVO.getIa()));
    String password = new String(Base64.getDecoder().decode(loginVO.getIp()));
    String vercode = new String(Base64.getDecoder().decode(loginVO.getVc()));
    String vercodeToken = new String(Base64.getDecoder().decode(loginVO.getVt()));
    
  2. 验证码校验:从Redis中根据验证码Token获取存储的验证码,并与用户输入的验证码进行比对。如果验证码不匹配,抛出CODE_ERROR异常。

    String code = redisTemplate.opsForValue().get(vercodeToken);
    if (ObjectUtil.isEmpty(code) || !StrUtil.equalsIgnoreCase(code,vercode)){
        throw new QLException(ExceptionEnum.CODE_ERROR);
    }
    
  3. 用户信息查询:根据用户名查询用户信息。如果用户不存在,抛出USER_NOT_NULL异常。

    LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
    userWrapper.eq(SysUser::getLoginUsername,username);
    SysUser sysUser = this.getOne(userWrapper);
    if (ObjectUtil.isEmpty(sysUser)){
        throw new QLException(USER_NOT_NULL);
    }
    
  4. 平台类型校验:检查用户所属平台是否与系统类型一致,如果不一致,抛出SYSTEM_TYPE_ERROR异常。

    String sysType = sysUser.getSysType();
    if (!ObjectUtil.equal(sysType,SYSTRM_TYPE)){
        throw new QLException(SYSTEM_TYPE_ERROR);
    }
    
  5. 密码校验:查询用户的认证信息,获取盐值和加密后的密码。将用户输入的密码与盐值拼接后进行哈希计算,并与数据库中存储的密码进行比对。如果密码不匹配,抛出USER_NOT_NULL异常。

    LambdaQueryWrapper<SysUserAuth> userAuthWrapper = new LambdaQueryWrapper<>();
    userAuthWrapper.eq(SysUserAuth::getUserId, sysUserId);
    SysUserAuth userAuth = userAuthService.getOne(userAuthWrapper);
    String credential = userAuth.getCredential();
    String salt = userAuth.getSalt();
    String SaltPassword = password + salt;
    
    boolean isTrue = PasswordUtil.verifyPassword(SaltPassword, credential);
    if (!isTrue){
        throw new QLException(USER_NOT_NULL);
    }
    
  6. 返回登录结果:如果所有校验通过,返回LoginDTO对象,包含用户的基本信息和登录凭证。

    LoginDTO loginDTO = new LoginDTO();
    loginDTO.setUsername(username);
    loginDTO.setPassword(password);
    loginDTO.setVercode(vercode);
    loginDTO.setVercodeToken(vercodeToken);
    loginDTO.setUserId(sysUser.getSysUserId());
    
    return loginDTO;
    
1.2 验证码生成

getVercode方法负责生成图片验证码,并将验证码存储到Redis中。具体流程如下:

  1. 生成验证码图片:使用CaptchaUtil生成一个包含干扰线的验证码图片,并设置背景颜色为白色。

    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(120, 40, 4, 5);
    captcha.setBackground(Color.white);
    
  2. 生成验证码Token:使用雪花算法生成一个唯一的Token,作为验证码的标识。

    long nextId = idWorker.snowflake().nextId();
    String sessionId = CHECK_PREFIX + String.valueOf(nextId);
    
  3. 存储验证码:将验证码和Token存储到Redis中,设置过期时间为1分钟。

    redisTemplate.opsForValue().set(sessionId , code , 1 , TimeUnit.MINUTES);
    
  4. 返回验证码信息:将验证码图片的Base64编码、过期时间和Token封装到VerCodeDTO对象中返回。

    VerCodeDTO verCodeDTO = new VerCodeDTO();
    verCodeDTO.setImageBase64Data(fullImageBase64);
    verCodeDTO.setExpireTime(60);
    verCodeDTO.setVercodeToken(sessionId);
    
    return ResSerialization.success(verCodeDTO);
    

2. 用户管理功能

2.1 分页查询用户

selectUserByUserIdOrUserName方法实现了根据用户ID或用户名进行分页查询的功能。具体流程如下:

  1. 参数校验:检查分页参数是否为空,如果为空则设置默认值。

    if (ObjectUtil.isEmpty(stratPage)){
        stratPage = 1;
    }
    if (ObjectUtil.isEmpty(limit)){
        limit = 10;
    }
    
  2. 查询总条数:使用MyBatis Plus的count方法查询用户总数。

    Long count = this.count(null);
    total = Integer.valueOf(Math.toIntExact(count));
    
  3. 计算最大页数:根据总条数和每页大小计算最大页数,如果请求的页数超过最大页数,则设置为最大页数。

    Integer maxPage = (int) (total / limit) + 1;
    if (stratPage > maxPage){
        stratPage = maxPage;
    }
    
  4. 查询用户列表:调用userMapper.selectUserByUserIdOrUserName方法,根据用户ID或用户名进行模糊查询,并返回分页结果。

    Integer startSize = (stratPage - 1) * limit;
    records = userMapper.selectUserByUserIdOrUserName(userId,userName,startSize,limit);
    
  5. 返回结果:将查询结果封装到UserListDTO对象中返回。

    UserListDTO userListDTO = new UserListDTO();
    userListDTO.setCurrent(current);
    userListDTO.setTotal(total);
    userListDTO.setRecords(records);
    userListDTO.setHasNext(hasNext);
    
    return ResSerialization.success(userListDTO);
    

在这里插入图片描述

2.2 删除用户

deleteUser方法实现了删除用户的功能。具体流程如下:

  1. 删除用户信息:根据用户ID删除用户表中的记录。

    boolean isDelete = this.remove(new LambdaQueryWrapper<SysUser>().eq(SysUser::getSysUserId, userId));
    if (!isDelete){
        throw new QLException(USER_REMOVE_ERROR);
    }
    
  2. 删除用户认证信息:删除用户认证表中的记录。

    LambdaQueryWrapper<SysUserAuth> userAuthLambdaQueryWrapper = new LambdaQueryWrapper<>();
    int isDeletUserAuth = sysUserAuthMapper.delete(userAuthLambdaQueryWrapper);
    if (isDeletUserAuth == 0){
        throw new QLException(USER_REMOVE_ERROR);
    }
    
  3. 清除权限缓存:从Redis中删除该用户的权限缓存。

    String key = USER_ROLE_CACHE + userId;
    redisTemplate.delete(key);
    
  4. 返回结果:返回删除操作的结果。

    return ResSerialization.success();
    
2.3 更新用户信息

updataUser方法实现了更新用户信息的功能。具体流程如下:

  1. 查询用户信息:根据用户ID查询用户信息,如果用户不存在,抛出USER_UPDATE_IS_EXIST_ERROR异常。

    SysUser user = this.getById(userUpdateVO.getSysUserId());
    if (ObjectUtil.isEmpty(user)){
        throw new QLException(USER_UPDATE_IS_EXIST_ERROR);
    }
    
  2. 更新密码:如果请求中指定了重置密码或使用默认密码,则更新用户的密码。

    Boolean isDefaultPass = userUpdateVO.getDefaultPass();
    if (isDefaultPass){
        userAuthService.updateUserPassword(userId,DEFAULT_PASSWORD);
    }
    
    Boolean resetPass = userUpdateVO.getResetPass();
    if (resetPass != null && resetPass && !isDefaultPass){
        String confirmPwd = userUpdateVO.getConfirmPwd();
        String password = new String(Base64.getDecoder().decode(confirmPwd));
        userAuthService.updateUserPassword(userId,password);
    }
    
  3. 更新用户信息:将UserUpdateVO中的属性复制到SysUser对象中,并更新用户表。

    SysUser sysUser = BeanUtil.copyProperties(userUpdateVO, SysUser.class);
    sysUser.setIsAdmin(userUpdateVO.getIsAdmin());
    LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
    sysUserLambdaQueryWrapper.eq(SysUser::getSysUserId,sysUserId);
    
    OperationUtil.executeOperation(() -> this.update(sysUser, sysUserLambdaQueryWrapper),USER_MSG_UPDATE_ERROR);
    
  4. 返回结果:返回更新操作的结果。

    return ResSerialization.success();
    
2.4 新增用户

insertUser方法实现了新增用户的功能。具体流程如下:

  1. 校验手机号和用户名:检查手机号和用户名是否已存在,如果存在则抛出相应的异常。

    LambdaQueryWrapper<SysUser> checkPhoneWrapper = new LambdaQueryWrapper<>();
    checkPhoneWrapper.eq(SysUser::getTelphone,telphone);
    SysUser checkUserPhoneObj = this.getOne(checkPhoneWrapper);
    if (ObjectUtil.isNotEmpty(checkUserPhoneObj)){
        throw new QLException(USER_PHONE_EXIST);
    }
    
    LambdaQueryWrapper<SysUser> checkUsernameWrapper = new LambdaQueryWrapper<>();
    checkUsernameWrapper.eq(SysUser::getTelphone,userInsertVO.getTelphone());
    SysUser checkUserNameObj = this.getOne(checkUsernameWrapper);
    if (ObjectUtil.isNotEmpty(checkUserNameObj)){
        throw new QLException(USER_NAME_EXIST);
    }
    
  2. 保存用户信息:将UserInsertVO中的属性复制到SysUser对象中,并设置创建时间和更新时间。

    SysUser sysUser = BeanUtil.copyProperties(userInsertVO, SysUser.class);
    Date date = new Date();
    sysUser.setCreatedAt(date);
    sysUser.setUpdatedAt(date);
    sysUser.setIsAdmin(userInsertVO.getIsAdmin());
    sysUser.setSysType(SYSTEM_TYPE_MGR);
    
    OperationUtil.executeOperation(() -> this.save(sysUser),USER_SAVE_ERROR);
    
  3. 保存用户认证信息:生成盐值,对默认密码进行加密,并保存到用户认证表中。

    SysUserAuth sysUserAuth = new SysUserAuth();
    sysUserAuth.setUserId(sysUser.getSysUserId());
    
    String salt = IdUtil.fastSimpleUUID().substring(0, 6);
    sysUserAuth.setSalt(salt);
    
    String password = DEFAULT_PASSWORD + salt;
    String pw = PasswordUtil.hashPassword(password);
    sysUserAuth.setCredential(pw);
    
    sysUserAuth.setSysType(SYSTEM_TYPE_MGR);
    sysUserAuth.setIdentifier(userInsertVO.getLoginUsername());
    sysUserAuth.setIdentityType(IDENTITY_TYPE_ACCOUNT);
    
    OperationUtil.executeOperation(() -> userAuthService.save(sysUserAuth) ,USER_SAVE_ERROR);
    
  4. 返回结果:返回新增操作的结果。

    return ResSerialization.success();
    

在这里插入图片描述

2.5 修改用户状态

updataUserState方法实现了修改用户状态的功能。具体流程如下:

  1. 更新用户状态:根据用户ID和请求中的状态值更新用户的状态。

    Integer state = hashMap.get("state");
    SysUser sysUser = new SysUser();
    sysUser.setState(state);
    LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
    sysUserLambdaQueryWrapper.eq(SysUser::getSysUserId,userId);
    
    OperationUtil.executeOperation(() -> this.update(sysUser, sysUserLambdaQueryWrapper),USER_STATUS_UPDATE_ERROR);
    
  2. 返回结果:返回更新操作的结果。

    return ResSerialization.success();
    
2.6 查询用户详情

selectUserDetial方法实现了查询用户详情的功能。具体流程如下:

  1. 参数校验:检查用户ID是否为空,如果为空则抛出PARAMS_NOT_NULL异常。

    if (userId == null){
        throw new QLException(PARAMS_NOT_NULL);
    }
    
  2. 查询用户信息:根据用户ID查询用户信息。

    SysUser sysUser = this.getById(userId);
    
  3. 返回结果:返回查询到的用户信息。

    return ResSerialization.success(sysUser);
    

3. 权限控制

UserController中,使用了SaCheckRole注解进行权限控制。例如,删除用户和修改用户状态的操作需要特定的角色权限才能执行。通过StpUtil.getLoginIdAsLong()方法获取当前登录用户的ID,并进行权限校验。

@SaCheckRole(value = {"admin", "super_admin"}, mode = SaMode.OR)
@DeleteMapping("/{userId}")
ResSerialization<String> deleteUser(@PathVariable Long userId){
    // 删除用户逻辑
}

@SaCheckRole(value = {"admin", "super_admin"}, mode = SaMode.OR)
@PutMapping("/status/{userId}")
ResSerialization<String> updataUserState(@PathVariable Long userId, @RequestBody HashMap<String , Integer> hashMap){
    // 修改用户状态逻辑
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攒了一袋星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值