springboot和shiro实现角色和权限认证

首先,需要在MySQL数据库中创建五个表,分别为user、user_role、role、permission、role_permission表;
user表需要的基本字段:id, username, password, createtime;
在这里插入图片描述
user_role表需要的基本字段:user_id, role_id;
在这里插入图片描述
role表需要的基本字段:role_id, role_name, role_key(角色权限字符串,为admin或者common), remark;
在这里插入图片描述
permission表需要的基本字段:id, perms, url;
在这里插入图片描述
role_permission表需要的基本字段:id, role_id, permission_id

在这里插入图片描述
在user实体类中添加list类型的role使多表查询时候进行连接
在这里插入图片描述
在role实体类中添加list类型的permission使多表查询时候进行连接
在这里插入图片描述
查询角色授权和权限授权的sql语句

    <!--多表联查查询用户角色授权-->
   <select id="queryUserRoleById" parameterType="integer" resultMap="RoleMap">
        SELECT DISTINCT *
        FROM role r
        LEFT JOIN user_role ur ON ur.role_id = r.role_id
        LEFT JOIN user us ON us.id = ur.user_id
        WHERE us.id = #{userid}
    </select>

 <!--多表联查查询用户权限授权-->
    <select id="queryPermsByUserId" resultType="string" parameterType="integer">
        SELECT distinct pr.perms
        FROM permission pr
        LEFT JOIN role_permission rp ON pr.id = rp.permission_id
        LEFT JOIN role r ON rp.role_id = r.role_id
        LEFT JOIN user_role ur ON r.role_id = ur.role_id
        LEFT JOIN user us ON us.id = ur.user_id
        WHERE us.id = #{id}
    </select>

Service层的写法


   /**
     * 根据用户ID查询角色
     * 这个方法写在role的service层
     * @param userId 用户ID
     * @return 权限列表
     */
    Set<String> selectRoleKeys(Integer userId);

 /**
     * 根据用户ID查询权限
     * 这个方法写在permission的service层
     * @param userId 用户ID
     * @return 权限列表
     */
    Set<String> selectPermsByUserId(Integer userId);

impl的写法

    /**
     * 根据用户ID查询角色
     *这个方法写在role的impl层
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRoleKeys(Integer userId) {
        List<Role> perms = roleDao.queryUserRoleById(userId);
        Set<String> permsSet = new HashSet<>();
        for (Role perm : perms) {
            if (perm!=null) {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }

  /**
     * 根据用户ID查询权限
     * 这个方法写在permission的impl层
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectPermsByUserId(Integer userId) {
        List<String> perms = permissionDao.queryPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

在自定义的realm中的doGetAuthorizationInfo方法中进行角色和权限的授权

 /**
     * 执行授权逻辑
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        LOGGER.info("执行授权逻辑");
        // 角色列表
        Set<String> roles;
        // 权限列表
        Set<String> perms;
        //        给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
//        获取SimpleAuthenticationInfo方法的第一个参数的内容
        Object obj =subject.getPrincipal();
        User user;
        if(obj instanceof User) {
            user = (User) obj;
            LOGGER.info("登录成功后类型正确获取的用户信息:right-- {}",JSON.toJSONString(user));
        } else {
            user = JSON.parseObject(JSON.toJSON(obj).toString(), User.class);
            LOGGER.info("登录成功后类型错误获取的用户信息:worry-- {}",JSON.toJSONString(user));
        }
        subject.getSession().setAttribute("user",user);
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            info.addRole("admin");
            info.addStringPermission("*:*:*");
        } else {
            roles = roleService.selectRoleKeys(user.getId());
            perms = permissionService.selectPermsByUserId(user.getId());
            LOGGER.info("用户角色信息:{}",roles);
            LOGGER.info("用户权限信息:{}",perms);
            // 角色加入AuthorizationInfo认证对象
            info.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            info.setStringPermissions(perms);
        }
        return info;
    }

因为将缓存存储到Redis中,取出的时候devtools热部署会提示类型转换错误,所有需要判断取出的类型是否正确,如果不正确需要将它强制类型转换成需要的数据格式。

判断是否是管理员的isAdmin()方法的写法,写在user的实体类中

 public static boolean isAdmin(Integer userId) {
        return userId != null && 1L == userId;
    }

    public boolean isAdmin() {
        return isAdmin(this.id);
    }

使用方法就是在controller层的方法上添加@RequiresPermissions(value = {“user:add”})注解或者 @RequiresRoles(value = “{admin}”)注解,让用户拥有value属性中的值得时候才能拥有权限访问该方法,否则没法访问。

为了让注解生效,需要在ShiroConfig的配置类中进行配置

  /**
     * 开启shiro 注解模式
     * 可以在controller中的方法前加上注解
     * 如 @RequiresPermissions("userInfo:add")
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

本文参考若依后台网站的例子完成
网站地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值