spring boot 登入权限RBAC模式
首先准备好5张表
user_info表,用户的信息表
role表,角色表(比如超级管理员、管理员、审核员、采购......)
创建user_role表,user_info表,role表的中间表
注意了,role_id和user_id是 user_info表和role表的关联id
auth_info表 菜单权限
创建roler_ayth表 ,auth表和role表的中间表
注意了,role_id和auth_id是 role_id表和auth_info表的关联id
也就是用户和角色有和中间表,角色和菜单表有个中间表
有表了我们开始做菜单树
1、创建实体类,mapper,service实现接口,impl实现类,映射文件mapper
博主用的是MyBatisCodeHelperPro插件,用逆向工程也就是从菜单树开始查询(MybatisX、Mybatis puls、Mybatis..插件必须卸载会冲突的,新手可以试用7天,价格在59人民币一年这样)
首先链接数据源
找到菜单权限auth_info表 右键
最后确定
这就是我们说的实体类,mapper,service实现接口,impl实现类,映射文件mapper
2、AuthInfoMapper类
package com.pn.service;
import com.pn.entity.AuthInfo;
import java.util.List;
public interface AuthInfoService{
public List<AuthInfo> queryAuthInfoByUid(Integer userId);
}
3、AuthInfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pn.mapper.AuthInfoMapper">
<!-- 根据用户ID查用户权限菜单-->
<!-- 得出合法行这个是固定的: select t3.* from user_role t1, role_auth t2, auth_info t3
where t1.role_id = t2.role_id and t2.auth_id = t3.auth_id and t1.user_id = #{userId} -->
<!-- 其他条件根据自己的表来,比如博主这个t3.auth_state=1是说明开启的 -->
<select id="getAuthInfoByUid" resultType="AuthInfo">
select t3.* from user_role t1, role_auth t2, auth_info t3
where t1.role_id = t2.role_id and t2.auth_id = t3.auth_id
and t3.auth_state = 1
and t3.auth_type != 3
and t1.user_id = #{userId}
</select>
</mapper>
4、AuthInfoService 实现类接口
package com.pn.service;
import com.pn.entity.AuthInfo;
import java.util.List;
public interface AuthInfoService{
public List<AuthInfo> queryAuthInfoByUid(Integer userId);
}
5、AuthInfoServiceImpl 实现类
package com.pn.service.impl;
import com.alibaba.fastjson.JSON;
import com.pn.entity.AuthInfo;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.pn.mapper.AuthInfoMapper;
import com.pn.service.AuthInfoService;
import org.springframework.util.StringUtils;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@Service
public class AuthInfoServiceImpl implements AuthInfoService{
@Autowired
private AuthInfoMapper authInfoMapper;
// 0库 博主用的是自己封装好的redis分库的,可以自己用自己的,也可以不用
//@Autowired
//@Qualifier("reactiveRedisTemplateDb0")
//private ReactiveRedisTemplate<String, Object> redis;
/**
* 查询用户菜单数的业务方法
* @param userId
* @return
*/
@Override
public List<AuthInfo> queryAuthInfoByUid(Integer userId) {
//先从redis查缓存,因为权限很少改动,所有放缓存,
//String authTerrJson = (String) redis.opsForValue().get("authTree:"+userId).block();
//有的话string转json给前端
//if (StringUtils.hasText(authTerrJson)) {
// return JSON.parseArray(authTerrJson, AuthInfo.class);
//}
//查redis无缓存,查数据库
List<AuthInfo> allauthInfo = authInfoMapper.getAuthInfoByUid(userId);
// 将查出的菜单List<AuthInfo>转成菜单树,需要递归算法
List<AuthInfo> authInfoList = allAuthToAuthTree(allauthInfo,0);
// 查出的菜单树存redis,并设置有效期
//redis.opsForValue().set("authTree:"+userId, JSON.toJSONString(authInfoList), Duration.ofSeconds(3600*24)).subscribe();
return authInfoList;
}
// 递归算法,必须是私有的
private List<AuthInfo> allAuthToAuthTree(List<AuthInfo> allauthInfo, Integer pid) {
//查出一级菜单
List<AuthInfo> allauthInfoList = new ArrayList<>();
for (AuthInfo authInfo : allauthInfo) {
if (authInfo.getParentId().equals(pid)) {
allauthInfoList.add(authInfo);
}
}
// 从一级菜单拿二级菜单
for (AuthInfo firstauthInfo : allauthInfoList) {
List<AuthInfo> firstauthInfoList = allAuthToAuthTree(allauthInfo,firstauthInfo.getAuthId());
firstauthInfo.setChildAuth(firstauthInfoList);
}
//返回菜单树
return allauthInfoList;
}
}
6、AuthInfo实体类
package com.pn.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 权限表
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AuthInfo implements Serializable {
private Integer authId;
/**
* 父id为空或为0,表示一级权限
*/
private Integer parentId;
private String authName;
private String authDesc;
private Integer authGrade;
/**
* 1 模块 、2 列表、 3 按钮
*/
private String authType;
private String authUrl;
private String authCode;
private Integer authOrder;
/**
* 1 启用 、0 禁用
*/
private String authState;
private Integer createBy;
private Date createTime;
private Integer updateBy;
private Date updateTime;
/**
* 存放当前菜单下的所有子菜单
*/
private List<AuthInfo> childAuth;
}
7、最后控制器,更具自己的前端给到的数据写
/**
* 用户权限
*/
// 注入UserService接口
@Autowired
private AuthInfoService authInfoService;
@RequestMapping("user/auth-list")
public Result userAuthTree(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token) {
//获取到token,并解析
CurrentUser currentUser = tokenUtil.getCurrentUser(token);
// 主要是这个 接口传递用户id
List<AuthInfo> authInfos = authInfoService.queryAuthInfoByUid(currentUser.getUserId());
return Result.ok("获取成功",authInfos);
}