首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐
2025年5月9日 星期五 6:15pm

权限控制方案之——集成shiro

  • 25-03-02 15:02
  • 3250
  • 7976
blog.csdn.net

概述:

         上一篇文章中我们介绍的权限控制方案的实现方式是通过URL拦截实现的,这里介绍通过shiro实现权限控制。shiro是apache下的开源的权限管理框架。

Shiro架构:

        

         Subject:主体,是用户和程序的统一抽象。

         SecurityManager:安全管理器,认证和授权的核心处理类。

         Authenticator:认证器,主体认证的处理类。

         Authorizer:授权器,主体授权的处理类。

         SessionManager:shiro提供的一套session管理机制。

         SessionDao:对于session的存储需要用到sessionDao。

         CacheManager;缓存管理器,主要对session和相关数据进行缓存管理。

         Realm:通过realm间接连接数据源,认证和授权需要通过realm存取认证和授权数据。

         Cryptography:密码管理器,shiro提供的一套加密解密组建。

 

整合shiro

         实现方式:

         1、通过shiro默认的IniRealm实现(开发中一般不用该方式),该方式需要将认证和授权信息配置在一个ini文件中,shiro会默认通过IniRealm读取该文件信息,实现认证。

         2、通过自定义Realm实现(一般都需要自定义Realm),自定义的Realm可以自定义认证和授权信息获取的方式(例如从数据库中查询),自定义的Realm继承AuthorizingRealm。

         这里主要介绍通过自定义Realm实现认证和授权的方式。下面通过将shiro整合到项目中的过程来介绍shiro的基本用法和shiro的工作原理。

         整合过程:

         1、添加jar包

         主要包括:shiro和spring整合的jar包,shiro和web应用整合的jar包和shiro一些基本的包。

         2、配置shiro的filter

         上篇文章我们介绍通过URL拦截中用到了拦截器,shiro内部也是用到了filter拦截进行实现。

         配置信息:

        

  1. <filter>
  2. <filter-name>shiroFilterfilter-name>
  3. <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
  4. <init-param>
  5. <param-name>targetFilterLifecycleparam-name>
  6. <param-value>trueparam-value>
  7. init-param>
  8. <init-param>
  9. <param-name>targetBeanNameparam-name>
  10. <param-value>shiroFilterparam-value>
  11. init-param>
  12. filter>
  13. <filter-mapping>
  14. <filter-name>shiroFilterfilter-name>
  15. <url-pattern>/*url-pattern>
  16. filter-mapping>


         3、applicationContext-shiro.xml

         在applicationContext-shiro.xml中配置shiroFilter需要的Bean及其他相关配置。

        

  1. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  2. <property name="securityManager" ref="securityManager" />
  3. <property name="loginUrl" value="/login.action" />
  4. <property name="successUrl" value="/first.action"/>
  5. <property name="unauthorizedUrl" value="/refuse.jsp" />
  6. <property name="filters">
  7. <map>
  8. <entry key="authc" value-ref="formAuthenticationFilter" />
  9. map>
  10. property>
  11. <property name="filterChainDefinitions">
  12. <value>
  13. /images/** = anon
  14. /js/** = anon
  15. /styles/** = anon
  16. /validatecode.jsp = anon
  17. /logout.action = logout
  18. /items/queryItems.action = perms[item:query]
  19. /items/editItems.action = perms[item:edit]
  20. /** = authc
  21. value>
  22. property>
  23. bean>
  24. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  25. <property name="realm" ref="customRealm" />
  26. <property name="cacheManager" ref="cacheManager"/>
  27. <property name="sessionManager" ref="sessionManager" />
  28. bean>
  29. <bean id="customRealm" class="cn.itcast.ssm.shiro.CustomRealm">
  30. <property name="credentialsMatcher" ref="credentialsMatcher"/>
  31. bean>
  32. <bean id="credentialsMatcher"
  33. class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
  34. <property name="hashAlgorithmName" value="md5" />
  35. <property name="hashIterations" value="1" />
  36. bean>
  37. <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
  38. <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
  39. bean>
  40. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
  41. <property name="globalSessionTimeout" value="600000"/>
  42. <property name="deleteInvalidSessions" value="true"/>
  43. bean>
  44. <bean id="formAuthenticationFilter"
  45. class="cn.itcast.ssm.shiro.CustomFormAuthenticationFilter ">
  46. <property name="usernameParam" value="username" />
  47. <property name="passwordParam" value="password" />
  48. bean>


         4、认证:

         实现原理:由上边的配置可知,当用户进行认证时,会去请求loginurl进行认证,中间FormAuthenticationFilter进行拦截,取出request中携带的username和password参数(注:这里默认为username和password,也可以自行配置),FormAuthenticationFilter会调用realm(自定义的吗?)进行认证,同时传给realm一个token参数,username和password封装在token中,realm会根据username查询用户信息,如果查询到则返回,如果查询不到则会返回null,这时FormAuthenticationFilter会向request中设置异常参数和信息。

        

  1. @Override
  2. protected AuthenticationInfo doGetAuthenticationInfo(
  3. AuthenticationToken token) throws AuthenticationException {
  4. //token中封装了用户输入的用户名和密码,从token中取出用户名
  5. String userCode = (String) token.getPrincipal();
  6. //根据用户输入的userCode从数据库查询
  7. SysUser sysUser = null;
  8. try {
  9. sysUser = sysService.findSysUserByUserCode(userCode);
  10. } catch (Exception e1) {
  11. e1.printStackTrace();
  12. }
  13. // 如果查询不到返回null
  14. if(sysUser==null){
  15. //此处返回null,ModularRealmAuthenticator抛出UnknownAccountException(用户不存在)异常
  16. return null;
  17. }
  18. //获取用户散列密码
  19. String password = sysUser.getPassword();
  20. //获取盐
  21. String salt = sysUser.getSalt();
  22. ActiveUser activeUser = new ActiveUser();
  23. activeUser.setUserid(sysUser.getId());
  24. activeUser.setUsercode(sysUser.getUsercode());
  25. activeUser.setUsername(sysUser.getUsername());
  26. List menus = null;
  27. try {
  28. //根据用户id取出菜单
  29. menus = sysService.findMenuListByUserId(sysUser.getId());
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. //用户菜单设置到activeUser
  34. activeUser.setMenus(menus);
  35. //将activeUser设置到simpleAuthenticationInfo返回
  36. SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
  37. activeUser, password,ByteSource.Util.bytes(salt), this.getName());
  38. return simpleAuthenticationInfo;
  39. }


         5、登出

         对于登出可以不用去实现具体的退出操作,只需要访问一个指定的登出的url,因为中间会由LogoutFilter拦截,同时清除session数据。配置方式见applicationContext-shiro.xml中的logout配置

         6、授权配置

         说明:对于shiro的授权配置有三种方法:

                  1、通过配置文件进行配置。

                  2、通过注解进行配置。

                  3、通过jsp标签进行配置。

         对于配置文件的配置方式见applicationContext-shiro.xml中的授权配置部分。

         实现原理为:在用户请求到/users/deleteUser.action时会被PermissionsAuthorizationFilter拦截,filter根据配置发现需要“item:query”权限,这时PermissionAuthorizationFilter会调用realm从数据库中获取权限信息,如果发现用户拥有该权限会放行,如果发现没有会转到前边配置中指定的refuse.jsp页面。

         7、权限判断

        

  1. @Override
  2. protected AuthorizationInfo doGetAuthorizationInfo(
  3. PrincipalCollection principals) {
  4. //获取身份信息
  5. ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
  6. List permissionList = null;
  7. try {
  8. //获取用户拥有的权限信息
  9. permissionList = sysService.findPermissionListByUserId(activeUser.getUserid());
  10. } catch (Exception e) {
  11. e.printStackTrace();
  12. }
  13. List permissions = new ArrayList();
  14. if(permissionList!=null){
  15. for(SysPermission sysPermission:permissionList){
  16. permissions.add(sysPermission.getPercode());
  17. }
  18. }
  19. //返回授权信息,将查询到的权限信息设置到simpleAuthorizationInfo中
  20. SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
  21. simpleAuthorizationInfo.addStringPermissions(permissions);
  22. return simpleAuthorizationInfo;
  23. }


         8、设置凭证匹配器

         由于在数据库中存放的密码是经过加密算法的散列值,所以在shiro也需要对取到的密码进行相同的加密算法才能进行密码比对,这里通过在配置文件中配置的凭证匹配器对加密算法进行配置,对于凭证匹配器的配置见applicationContext-shiro.xml。

         上边对于授权的方式我们使用的是通过配置文件进行实现的,但是这样的缺点在,URL和对应的权限成对配置,这样将造成很大的配置量,相对来说比较麻烦;下边我们说明一下如何通过注解的方式进行配置。

 

整合改进

         注解方式实现授权:

         上边介绍了对于shiro的授权配置有三种方式,上边的方式是通过配置文件的方式实现的,下边介绍一下如何通过注解方式和jsp标签方式进行授权配置。

         开启注解:

         由于注解方式内部使用了spring的AOP方式,所以需要首先开启spring的AOP,同时开启shiro的注解支持。配置如下:

        

  1. <aop:config proxy-target-class="true">aop:config>
  2. <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
  3. <property name="securityManager" ref="securityManager" />
  4. bean>


         注解使用:

         注解的使用方式为,在需要进行权限控制的方法上添加相应注解,注解的写法为:

         @RequiresPermissions(“users:delete”),表示执行此方法需要“users:delete”权限。


         Jsp标签实现授权:

         对于通过jsp标签实现授权需要引入shiro的自定义标签

         <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>

         标签使用:shiro提供的标签很多,这里介绍其中几个:

         1、认证成功后可以显示的内容放在内。

         2、当用户有指定角色时才显示的内容放在"角色名"> 内

         3、当用户有指定的权限时才显示的内容放在"item:query">内

         在实际应用当中,通过注解和jsp标签的方式相对多些。


         引入缓存:

         对于上边的使用,无论是通过何种方式配置的权限,存在一个较大的问题是,对于权限的判断,每次都需要realm从数据库中查询权限信息进行比对,这样对系统的性能消耗是很大的,为了解决该问题,我们为shiro引入缓存处理,这样就只需要在用户第一次访问时去查询数据库,再后边就可以直接从缓存中取,这里使用的是ehcache。

         1、添加ehcache的jar包。

         2、配置cacheManager,需要将cacheManager注入到securityManager中,对于相关配置见applicationContext-shiro.xml。

         3、创建shiro-ehcache.xml,定义ehcache的使用方案,具体配置如下:

        

  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  3. <diskStore path="F:\develop\ehcache" />
  4. <defaultCache
  5. maxElementsInMemory="1000"
  6. maxElementsOnDisk="10000000"
  7. eternal="false"
  8. overflowToDisk="false"
  9. diskPersistent="false"
  10. timeToIdleSeconds="120"
  11. timeToLiveSeconds="120"
  12. diskExpiryThreadIntervalSeconds="120"
  13. memoryStoreEvictionPolicy="LRU">
  14. defaultCache>
  15. ehcache>

         其他

         shiro提供了在用户退出后缓存的自动清空处理,然而,在用户登录期间对用户的缓存进行更新处理,需要调用realm的clearCached方法对缓存进行清空。

 

总结:

         对于利用shiro对权限的控制和前边基于URL拦截的控制进行对比来说,shiro的控制功能更加强大一些,但是对于框架的依赖性大些,虽然shiro本身是不依赖与其他框架的,但是这里和项目整合还是依赖了spring框架,在使用shiro时如果使用注解的方式进行权限控制会更加方便和直观。这里主要介绍了shiro和项目整合中的基本用法,其中对于认证和授权的流程在后边进行介绍,这些只是shiro的一些基本用法,对于shiro的其他应用特点还有待继续了解和学习,也希望这篇文章可以对你有所帮助吧。

 

文章知识点与官方知识档案匹配,可进一步学习相关知识
Java技能树控制执行流程if-else148947 人正在系统学习中
注:本文转载自blog.csdn.net的任长江的文章"http://blog.csdn.net/rcj183419/article/details/68066162#"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top