项目Github地址: https://github.com/baiye21/ShiroDemo

  1. SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (一) 简介与配置

  2. SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (二) 认证

  3. SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (三) 鉴权

一,ShiroFilterFactoryBean配置

FilterChainDefinitionMap排除需要权限才能访问的URL,这样才能进入自定义过滤器JwtFilter中进行后续验证。

比如,测试权限的URl为/role/OneRole.do,它不需要写入FilterChainDefinitionMap中,如下图

二,自定义ShiroSessionManager

认证成功后,将shiro生成的sessionid保存到了access_token中,所以携带token访问时,需要从token将其取出。

com.demo.config.ShiroConfig中

  /*** SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)*/@Beanpublic SecurityManager securityManager(@Qualifier("passwordRealm") PasswordRealm passwordRealm,@Qualifier("jwtRealm") JwtRealm jwtRealm,@Qualifier("demoRealm") DemoRealm demoRealm,@Qualifier("userModularRealmAuthenticator") UserModularRealmAuthenticator userModularRealmAuthenticator) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置realmsecurityManager.setAuthenticator(userModularRealmAuthenticator);List<Realm> realms = new ArrayList<>();// 添加多个realmrealms.add(passwordRealm);realms.add(jwtRealm);realms.add(demoRealm);/** 关闭shiro自带的session,详情见文档* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29*/DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();// 不需要将 Shiro Session 中的东西存到任何地方(包括 Http Session 中)defaultSessionStorageEvaluator.setSessionStorageEnabled(false);subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);securityManager.setSubjectDAO(subjectDAO);//  自定义sessionManagersecurityManager.setSessionManager(shiroSessionManager());// securityManager设置自定义认证规则securityManager.setRealms(realms);return securityManager;}@Beanpublic ShiroSessionManager shiroSessionManager() {ShiroSessionManager shiroSessionManager = new ShiroSessionManager();// TODO redis 配置session持久化shiroSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());return shiroSessionManager;}

com.demo.shiro.ShiroSessionManager

@Slf4j
public class ShiroSessionManager extends DefaultWebSessionManager {public ShiroSessionManager() {super();}private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";@Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {// 如果请求头中有 AuthorizationString token = WebUtils.toHttp(request).getHeader(Const.TOKEN_HEADER_NAME);if (!StringUtils.isEmpty(token)) {if (JwtUtil.verify(token, Const.TOKEN_SECRET)) {String id = JwtUtil.getClaim(token, Const.JSESSIONID);log.debug("ShiroSessionManager从http header 取出token中的JSESSIONID:{}", id);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return id;}return super.getSessionId(request, response);} else {// 否则按默认规则从cookie取sessionIdreturn super.getSessionId(request, response);}}}

三,JwtFilter执行executeLogin();

/*** 执行登录认证* * @param request* @param response* @param mappedValue* @return 是否成功*/@Override// 这个方法判断 尝试进行登录的操作,如果token存在,那么进行提交登录,如果不存在说明可能是正在进行登录或者做其它的事情 直接放过即可protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {try {executeLogin(request, response);return true;} catch (Exception e) {// return false;// throw new AuthenticationException("Token失效请重新登录");// 认证出现异常,传递错误信息msgString msg = e.getMessage();// 获取应用异常(该Cause是导致抛出此throwable(异常)的throwable(异常))Throwable throwable = e.getCause();if (throwable != null && throwable instanceof SignatureVerificationException) {// 该异常为JWT的AccessToken认证失败(Token或者密钥不正确)msg = "token或者密钥不正确(" + throwable.getMessage() + ")";} else if (throwable != null && throwable instanceof TokenExpiredException) {// 该异常为JWT的AccessToken已过期(TokenExpiredException),// 判断RefreshToken未过期就进行AccessToken刷新if (this.refreshToken(request, response)) {return true;} else {msg = "token已过期(" + throwable.getMessage() + ")";}} else {// 应用异常不为空if (throwable != null) {// 获取应用异常msgmsg = throwable.getMessage();}}/*** 错误两种处理方式* 1. 将非法请求转发到/401的Controller处理,抛出自定义无权访问异常被全局捕捉再返回Response信息* 2. 无需转发,直接返回Response信息 一般使用第二种(更方便)*/// 直接返回Response信息this.response401(request, response, msg);return false;}}

四,UserModularRealmAuthenticator加载DemoRealm

login的时候创建的是CustomizedToken,之后的请求Header携带的都是JwtToken,因此区分加载哪一种类型的Realm。

     if(authenticationToken instanceof  JwtToken) {log.debug("验证的Token类型是:{}", "JwtToken");typeRealms.clear();// 获取header部的token进行强制类型转换JwtToken jwtToken = (JwtToken) authenticationToken;for (Realm realm : realms) {if (realm.getName().contains("Demo")) {typeRealms.add(realm);}}return doSingleRealmAuthentication(typeRealms.iterator().next(), jwtToken);}

五,DemoRealm进行鉴权(doGetAuthorizationInfo)

/*** 功能: 获取用户权限信息,包括角色以及权限。只有当触发检测用户权限时才会调用此方法,例如checkRole,checkPermission** @param principals* @return AuthorizationInfo 权限信息*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {log.info("demoRealm doGetAuthorizationInfo 用户赋权 ");String userid = null;if (principals != null) {// 此处的principals为 UserMasterObject PrimaryPrincipal = principals.getPrimaryPrincipal();if (PrimaryPrincipal instanceof UserMaster) {UserMaster userMaster = (UserMaster) PrimaryPrincipal;userid = userMaster.getUserId();} else {// 此处的principals为tokenuserid = JwtUtil.getClaim(principals.toString(), Const.TOKEN_CLAIM_USERID);}}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 获取用户角色与权限信息UserAccessInfo userAccessInfo = iUserService.getUserAccessInfo(userid);/*** 设置用户拥有的角色集合,<br>* * accountType = 1 管理员 admin <br>* accountType = 2 领导  Leader <br>* accountType = 3 普通用户 user <br>* */info.setRoles(userAccessInfo.getRoleSet());// 设置用户拥有的权限集合info.addStringPermissions(userAccessInfo.getPermissionSet());return info;}

六,getUserAccessInfo

com.demo.service.impl.UserServiceImpl的getUserAccessInfo方法

/*** 获取用户角色set与权限set** @param userId* @return*/public UserAccessInfo getUserAccessInfo(String userId) {UserAccessInfo userAccessInfo = new UserAccessInfo();// 用户角色setSet<String> roleSet = new HashSet<String>();// 用户权限setSet<String> permissionSet = new HashSet<String>();UserMaster userMaster = userMasterMapper.selectByUserId(userId);// 账号类型String accountType = userMaster.getAccountType();// 管理员 accountType = 1if (Const.ADMIN_USER_CODE.equals(accountType)) {// adminroleSet.add(Const.ADMIN_USER);// Leader accountType = 2} else if (Const.LEADWER_USER_CODE.equals(accountType)) {// LeaderroleSet.add(Const.LEADER_USER);// 普通用户 accountType = 3} else if (Const.NORMAL_USER_CODE.equals(accountType)) {// userroleSet.add(Const.NORMAL_USER);}// 用户权限类型String permissionType = userMaster.getPermissionType();if (Const.LEVEL_001_CODE.equals(permissionType)) {permissionSet.add(Const.LEVEL_001);} else if (Const.LEVEL_002_CODE.equals(permissionType)) {permissionSet.add(Const.LEVEL_002);} else if (Const.LEVEL_003_CODE.equals(permissionType)) {permissionSet.add(Const.LEVEL_003);} else if (Const.LEVEL_004_CODE.equals(permissionType)) {permissionSet.add(Const.LEVEL_004);} else if (Const.LEVEL_005_CODE.equals(permissionType)) {permissionSet.add(Const.LEVEL_005);}userAccessInfo.setRoleSet(roleSet);userAccessInfo.setPermissionSet(permissionSet);return userAccessInfo;}

七,简单测试

测试用的TestRoleController ,主要测试以下权限:

ps:由于之前测试用户表设计一个用户只对应一种角色一种权限,所以第四个测试只有失败的情况

  1.   @RequiresRoles(Const.ADMIN_USER)  角色-- 只有管理员用户才能访问
  2.   @RequiresRoles(value = { Const.ADMIN_USER, Const.LEADER_USER }, logical = Logical.OR)  角色-- 管理员用户和Leader用户都能访问
  3.   @RequiresPermissions(Const.LEVEL_004)  权限-- 001 能访问
  4.   @RequiresPermissions(value = {Const.LEVEL_004,Const.LEVEL_005}, logical = Logical.AND)  权限-- 004 且 005 才能访问
/** Author  : baiye <baiye_21@163.com>Time    : 2021/06/30Function:
*/
@RestController
@RequestMapping("/role/")
public class TestRoleController {/*** 只有管理员用户才能访问** @return* @throws Exception*/@RequiresRoles(Const.ADMIN_USER)@RequestMapping(value = "/OneRole.do", method = RequestMethod.POST)@ResponseBodypublic ServerResponse<String> OneRole() throws Exception {return ServerResponse.createBySuccessMessage("One Role");}/*** 管理员用户和Leader用户能访问** @return* @throws Exception*/@RequiresRoles(value = { Const.ADMIN_USER, Const.LEADER_USER }, logical = Logical.OR)@RequestMapping(value = "/TwoRole.do", method = RequestMethod.POST)@ResponseBodypublic ServerResponse<String> TwoRole() throws Exception {return ServerResponse.createBySuccessMessage("Two Role");}/*** Permission 001 能访问** @return* @throws Exception*/@RequiresPermissions(Const.LEVEL_004)@RequestMapping(value = "/OnePermission.do", method = RequestMethod.POST)@ResponseBodypublic ServerResponse<String> OnePermission() throws Exception {return ServerResponse.createBySuccessMessage("One Permission");}/*** Permission 004 且 005 能访问** @return* @throws Exception*/@RequiresPermissions(value = {Const.LEVEL_004,Const.LEVEL_005}, logical = Logical.AND)@RequestMapping(value = "/TwoPermission.do", method = RequestMethod.POST)@ResponseBodypublic ServerResponse<String> TwoPermission() throws Exception {return ServerResponse.createBySuccessMessage("Two Permission");}
}

准备的测试用户

使用demo002用户登录

localhost:9999/role/OneRole.do

localhost:9999/role/TwoRole.do

localhost:9999/role/OnePermission.do

localhost:9999/role/TwoPermission.do

SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (三) 鉴权相关推荐

  1. Shiro+JWT+Redis实现用户校验

    Shiro基础知识 1. shiro基本功能 认证:验证用户登录认证: 授权:即权限验证,对已经登录的用户验证是否有相应的权限: 会话管理:用户在认证成功之后创建会话,当前用户的所有信息都会保存在这个 ...

  2. PMS权限管理和鉴权过程

    一.权限的管理基础知识 1.系统的权限机制分为:权限解析.权限分配.鉴权.动态添加权限 2.PermissionInfo :  PackageParser.Permission中包含一个对应的Perm ...

  3. Android pms权限管理,PMS权限管理和鉴权过程

    一.权限的管理基础知识 1.系统的权限机制分为:权限解析.权限分配.鉴权.动态添加权限 2.PermissionInfo :  PackageParser.Permission中包含一个对应的Perm ...

  4. springboot整合shiro + jwt + redis实现权限认证(上手即用)

    目录 前言 项目结构 依赖导入 建数据库表 建表语句 使用插件生成增删改查 添加MyRealm 添加ShiroConfig 添加JwtFilter JWT相关得类 JwtToken JwtAudien ...

  5. SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    GitHub源码地址:知了一笑 https://github.com/cicadasmile/middle-ware-parent 一.Shiro简介 1.基础概念 Apache Shiro是一个强大 ...

  6. 基于shiro+jwt的真正rest url权限管理,前后端分离

    代码地址如下: http://www.demodashi.com/demo/13277.html bootshiro & usthe bootshiro是基于springboot+shiro+ ...

  7. springBoot中shiro与Redis整合的配置文件

                                                                 springBoot中shiro与Redis整合的配置文件 整合依赖: < ...

  8. 关于SpringBoot整合Shiro并入redis缓存

    关于SpringBoot整合Shiro并入redis缓存 最近做一个小项目加入shiro权限框架, Shiro是Apache下的一个开源项目,提供了认证.授权.加密.会话管理,与spring Secu ...

  9. 基于LDAP的WebLogic虚拟化统一用户权限管理

    0 引言 随着国家电网SG186工程建设的深入,企业门户的建设也开始由省电力公司一级向地市供电公司一级延伸.根据国家电网门户典型设计,河南省电力公司采用了虚拟方式建设全省各地市门户.由于虚拟门户的软. ...

最新文章

  1. java云服务器系统选择,java云服务器系统选择
  2. IIRF重写在asp.net4.0+IIS6中部分失败的解决方案
  3. 对称密码算法Rijndael解析—加密
  4. yii2 windows 安装
  5. Qt多线程 TCP 服务端
  6. [攻防世界 pwn]——pwn1(内涵peak小知识)
  7. 757计算机电子元件,飞行员的好帮手 波音757的发动机指示与机组报警系统简介...
  8. python requests_一起看看Python之Requests库
  9. 计算机课程设计大全,单片机课程设计题目大全计算机软件及应用IT计算机专业资料-单片(10页)-原创力文档...
  10. abaqus模拟单向压缩实验
  11. edge浏览器设置启动时默认打开新标签页
  12. userAgent判断客户端,以及各个浏览器的ua
  13. c#语言猜数字游戏,C#实现猜数字游戏
  14. JAVA电商 B2B2C商城系统 多用户商城系统 直播带货 新零售商城 o2o商城 电子商务 拼团商城 分销商城 直播商城 短视频商城 springcloud商城 spring cloud商城
  15. Linux运维工程师学习大纲
  16. 共享红色理念创业计划书PPT模板
  17. 艾默生流量计校验功能
  18. MySQL免安装最新2021详细教程
  19. ubuntu16.04下编译ORB_SLAM3时出现的问题及解决方法
  20. 浏览器打开新窗口被拦截问题

热门文章

  1. 如何复制PPT的模板?
  2. ArcGis中已知经纬度坐标转任意坐标系(以点和80坐标系为讲解模板)
  3. 出手1000万美元,马云非洲之行交“学费”
  4. js验证16进制和十进制
  5. [DP之家]一个初学者想要的面试宝典
  6. 开源要自立?华为如何“复制”Google模式
  7. HTML 动画、3D学习之制作魔方练习
  8. 杭州服务器电销适合的系统,电销系统,可以这样用
  9. 开源数据大屏AJ-Report
  10. Nessus: 漏洞扫描器-网络取证工具