Loading... 简介:针对企业里比较常用的shiro权限控制框架进行展示说明 <div class="tip inlineBlock info simple"> 内容: 1. 基于基本的RBAC模型,引入mybatis plus做DAO层。 2. springboot整合shiro,完成权限控制。 3. 完成shiro的认证、授权 4. 使用redis做shiro的会话管理和缓存管理。 5. 了解thymeleaf中的权限控制。 </div> 视频地址:https://b23.tv/sQLkTqU 配套资料:https://pan.baidu.com/s/1jBgMnkD1qYZcfwv7lc938Q <div class="hideContent">此处内容需要评论回复后(审核通过)方可阅读。</div> # shiro权限控制 ## 1.权限控制 ### 1.1 什么是权限控制 白话文:控制某某用户可以/不可以访问某某功能。 我们今天的权限控制,实际上就是对资源加锁,每个锁都有一些规则,只有对应的钥匙才能打开,我们根据用户的角色,将钥匙分配给不同用户。 ### 1.2 权限控制的方式 1、基于过滤器进行控制。比如我们servlet中的filter 2、基于注解进行控制。可以借助spring的AOP进行控制。 3、直接在业务代码中判断(不可取) 4、页面标签的权限控制——不太常用。 > 1和2也是经常用的,会1和2基本可不用其他框架,完全可以自己写。如果想要简便可以使用框架,现在我们介绍shiro框架。 ## 2.shiro简介 ### 2.1 功能 #### 认证:即我们常说的登录 #### 授权:给予用户资源权限 #### 会话:当前认证用户会话 #### 缓存:缓存认证权限等 ### 2.2 shiro核心流程 #### 图示 ——这个图只要是用shiro必定逃离不了。 ![](https://blog.fivk.cn/usr/uploads/2023/09/166543643.png) 之后的知识有点难理解,可以先试试这个demo <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/1696.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/4.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">【知识总结】shiro的整合“心路历程”</p> <div class="inster-summary text-muted"> shiro的整合“心路历程”1.准备数据用户-角色-权限 RBAC模型用户角色权限luo用户管理员对后台用户的C... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> ### 2.3 权限控制方式: #### filter方式 ```java //设置过滤匹配路径和判断规则 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); filterChainDefinitionMap.put("/**", "anon");//可以匿名访问 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); ``` 其中,shiro的filter列表,盗了一张图: ![](https://blog.fivk.cn/usr/uploads/2023/09/71932105.png) | 过滤器别名 | 对应的过滤器 | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **anon** | org.apache.shiro.web.filter.authc.AnonymousFilter | | **authc** | [org.apache.shiro.web.filter.authc.FormAuthenticationFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authc/FormAuthenticationFilter.html) | | authcBasic | [ org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authc/BasicHttpAuthenticationFilter.html) | | **logout** | [org.apache.shiro.web.filter.authc.LogoutFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authc/LogoutFilter.html) | | noSessionCreation | [org.apache.shiro.web.filter.session.NoSessionCreationFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/session/NoSessionCreationFilter.html) | | **perms** | [org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authz/PermissionsAuthorizationFilter.html) | | port | [org.apache.shiro.web.filter.authz.PortFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authz/PermissionsAuthorizationFilter.html) | | rest | [org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authz/HttpMethodPermissionFilter.html) | | **roles** | [org.apache.shiro.web.filter.authz.RolesAuthorizationFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authz/RolesAuthorizationFilter.html) | | ssl | [org.apache.shiro.web.filter.authz.SslFilter](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authz/SslFilter.html) | | user | [org.apache.shiro.web.filter.authc.UserFilter](http://shiro.apache.org/static/1.3.2/apidocs/org/apache/shiro/web/filter/authc/UserFilter.html) | #### 注解方式 ```java //在具体的方法上添加注解 @RequiresAuthentication :表示当前Subject已经认证:Subject.isAuthenticated()返回true @RequiresUse:表示当前Subject已经身份验证或者通过记住我登录的 @RequiresGuest :表示当前Subject没有身份验证或通过记住我登录过,即是游客身份 @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND) @RequiresPermissions(value={“user:select”, “user:all”}, logical= Logical.OR) ``` 只是用注解是不生效的,需要添加配置 ```java /** * 注解支持: */ @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); defaultAAP.setProxyTargetClass(true); return defaultAAP; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } ``` #### 标签(了解) 注意,此处使用的是thymeleaf做视图界面展示,并非jsp ```html <!--输出当前用户信息,通常为登录帐号信息。如果存入的principal是对象,可以通过property取值--> <span> <shiro:principal property="username"/> </span> <!--验证当前用户是否拥有指定权限。 --> <a shiro:hasPermission="user:select" href="#" >查看用户列表</a><!-- 拥有权限 --> <!--与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。--> <p shiro:lacksPermission="user:del"> 没有权限 </p> <!--验证当前用户是否拥有以下所有权限。--> <p shiro:hasAllPermissions="user:view, user:add">拥有所有才能访问</p> <!--验证当前用户是否拥有以下任意一个权限。--> <p shiro:hasAnyPermissions="user:view, user:del">拥有任意一个即可访问</p> <!--验证当前用户是否属于该角色。--> <a shiro:hasRole="role_admin" href="#">是role_admin角色</a> <!--与hasRole标签逻辑相反,当用户不属于该角色时验证通过。--> <p shiro:lacksRole="role_admin">我没有role_admin角色</p> <!--验证当前用户是否属于以下所有角色。--> <p shiro:hasAllRoles="developer, admin"> 角色与判断 </p> <!--验证当前用户是否属于以下任意一个角色。--> <p shiro:hasAnyRoles="admin, vip, developer"> 角色或判断 </p> <!--验证当前用户是否为“访客”,即未认证(包含未记住)的用户。--> <p shiro:guest="">访客 未认证</a></p> <!--已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。--> <p shiro:authenticated=""> <span shiro:principal=""></span> </p> <!--未认证通过用户,与authenticated标签相对应。--> <!--与guest标签的区别是,该标签包含已记住用户。--> <p shiro:notAuthenticated=""> 未认证通过用户 </p> ``` ## 3.springboot整合shiro ### 3.1 SecurityManager ```java @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); List<Realm> realms = new ArrayList<Realm>(); realms.add(customRealm()); securityManager.setRealms(realms); securityManager.setSessionManager(sessionManager()); return securityManager; } ``` ### 3.2 Realm ```java //主要用作封装认证、授权信息,返回给安全管理器处理 @Bean public CustomRealm customRealm(){ CustomRealm customRealm = new CustomRealm(); //设置密码校验算法——需要和加密算法一致 customRealm.setCredentialsMatcher(credentialsMatcher()); return customRealm; } @Bean public CredentialsMatcher credentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法; // hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher; } ``` ### 3.3 ShiroFilter ```java @Bean public ShiroFilterFactoryBean shiroFilter2(SecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/admin/toPage"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //访问控制 filterChainDefinitionMap.put("/admin/toPage", "anon");//可以匿名访问 filterChainDefinitionMap.put("/admin/login", "anon");//可以匿名访问 filterChainDefinitionMap.put("/storage/list", "perms[user:select]");//可以匿名访问 // filterChainDefinitionMap.put("/", "anon");//可以匿名访问 filterChainDefinitionMap.put("/**", "anon");//可以匿名访问 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } ``` ### 3.4 SessionManager ```java @Bean public SessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); //设置会话过期时间 sessionManager.setGlobalSessionTimeout(3*60*1000); //默认半小时 sessionManager.setDeleteInvalidSessions(true); //默认自定调用SessionDAO的delete方法删除会话 //设置会话定时检查 sessionManager.setSessionValidationInterval(180000); //默认一小时 sessionManager.setSessionValidationSchedulerEnabled(true); return sessionManager; } @Bean public SessionDAO redisSessionDAO(){ ShiroSessionRedisDAO redisDAO = new ShiroSessionRedisDAO(); return redisDAO; } ``` ### 3.4 用户新增 在controller中接收新增用户后,交给service的saveAdmin做密码加密后保存 ```java public void saveAdmin(Administrator admin) { //对密码进行加密处理 //1.得到明文密码 String password = admin.getPassword(); //2.生成随机盐 4-8位的随机数字 String randomSalt = RandomStringUtils.randomNumeric(4, 8); admin.setPrivateSalt(randomSalt); //3.md5加密 添加随机盐,加密次数1次(当然,这个一次可以配置在配置文件在,此处注入读取) Md5Hash md5Hash = new Md5Hash(password,randomSalt,1); String hashPwd = md5Hash.toString(); admin.setPassword(hashPwd); userMapper.insert(admin); } ``` ### 3.5 用户登录 认证 ```java @Controller @RequestMapping("/admin") public class LoginController { @PostMapping("/login") public String login( @RequestParam("username") String username, @RequestParam("password") String password,Model map){ try { Subject subject = SecurityUtils.getSubject(); //处理登录的用户名密码token UsernamePasswordToken token = new UsernamePasswordToken(username, password); //登录(开始认证) subject.login(token); return "redirect:/admin/main"; }catch (UnknownAccountException ukactException){ //用户不存在异常 ukactException.printStackTrace(); map.addAttribute("err_msg","用户不存在"); return "login"; }catch (IncorrectCredentialsException credentialExctption){ credentialExctption.printStackTrace(); map.addAttribute("err_msg","密码错误"); return "login"; }catch (Exception e){ e.printStackTrace(); map.addAttribute("err_msg","服务器错误,请重试"); return "login"; } } } ``` ### 3.6 用户访问(权限控制) ## 4.其他 ### 4.1 thymeleaf中使用shiro标签的支持 依赖坐标: ```xml <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> ``` 配置支持: ```java @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } ``` ### 4.2 request判断ajax请求 ```java //通过头X-Requested-With=XMLHttpRequest来判断 request.getHeader("X-Requested-With"); ``` ``` 最后修改:2023 年 09 月 07 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏