SSM整合Shiro框架+Redis 实现权限管理

1.Shiro概述

Apache Shiro 是一个强大易用的 Java 安全框架

Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。

简介

Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。这不就是我们想要的嘛,而且 Shiro 的 API 也是非常简单;其基本功能点如下图所示:

组件描述
Authentication身份认证 / 登录,验证用户是不是拥有相应的身份
Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限
SessionManager

 

会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的。
		<p style="margin-left:0px;">&nbsp;</p>

		<p style="margin-left:0px;">&nbsp;</p>
		Web环境中可使用DefaultWebSessionManager。

		<p style="margin-left:0px;">&nbsp;</p>
		</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">SecurityManager</td>
		<td style="margin-left:0px;width:551px;">
		<p style="margin-left:0px;">&nbsp;</p>
		安全管理器,即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互。

		<p style="margin-left:0px;">&nbsp;</p>

		<p style="margin-left:0px;">&nbsp;</p>
		Web环境中可使用DefaultWebSecurityManager。

		<p style="margin-left:0px;">&nbsp;</p>
		</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">Realm</td>
		<td style="margin-left:0px;width:551px;">域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">Subject</td>
		<td style="margin-left:0px;width:551px;">主体,代表了当前 “用户”</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">SessionDAO</td>
		<td style="margin-left:0px;width:551px;">用于进行session序列化于反序列化的组件</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">CacheManager</td>
		<td style="margin-left:0px;width:551px;">用于进行缓存管理的组件</td>
	</tr><tr style="margin-left:0px;"><td style="margin-left:0px;width:298px;">Cache</td>
		<td style="margin-left:0px;width:551px;">用于直接进行缓存操作的组件</td>
	</tr></tbody></table></div><h2 style="margin-left:0px;"><a name="t3"></a>2.自定义组件介绍</h2>

整合框架中自定义Shiro组件全部位于com.brillilab.ssmdemo.common.shiro包中

子包描述
com.brillilab.ssmdemo.common.shiro.cache自定义缓存组件,用于进行认证信息、权限信息和会话信息的缓存操作
com.brillilab.ssmdemo.common.shiro.filter自定义权限过滤器
com.brillilab.ssmdemo.common.shiro.listenter自定义会话监听器
com.brillilab.ssmdemo.common.shiro.realms自定义Realms
com.brillilab.ssmdemo.common.shiro.session自定义Session缓存管理组件,用于进行Sesssion缓存的操作,主要组件为SessionDAO和SessionRepository
com.brillilab.ssmdemo.common.shiro.token自定义Token,使用不同的自定义Token可以实现不数据结构的Token
com.brillilab.ssmdemo.common.shiro.utils相关工具包

3.配置文件

(1)applicationContext-shiro.xml的编写


 
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p= "http://www.springframework.org/schema/p"
  5. xmlns:context= "http://www.springframework.org/schema/context"
  6. xmlns:util= "http://www.springframework.org/schema/util"
  7. xsi:schemaLocation= "http://www.springframework.org/schema/beans
  8. http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  9. http://www.springframework.org/schema/context
  10. http://www.springframework.org/schema/context/spring-context-3.1.xsd
  11. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
  12. <!-- (一)rememberMe管理器 -->
  13. <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
  14. <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->
  15. <property name="cipherKey"
  16. value= "#{T(org.apache.shiro.codec.Base64).decode('3AvVhmFLUs0KTA3Kprsdag==')}"/>
  17. <property name="cookie" ref="rememberMeCookie"/>
  18. </bean>
  19. <!-- 用户信息记住我功能的相关配置 -->
  20. <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
  21. <constructor-arg value="v_v-re-baidu"/>
  22. <property name="httpOnly" value="true"/>
  23. <!-- 配置存储rememberMe Cookie的domain为 一级域名
  24. <property name="domain" value=".itboy.net"/>
  25. -->
  26. <property name="maxAge" value="2592000"/> <!-- 30天时间,记住我30天 -->
  27. </bean>
  28. <!-- (二)SecurityManager -->
  29. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  30. <property name="realm" ref="userRealm"/>
  31. <property name="sessionManager" ref="sessionManager"/>
  32. <property name="rememberMeManager" ref="rememberMeManager"/>
  33. <property name="cacheManager" ref="customShiroCacheManager"/>
  34. </bean>
  35. <!-- ShiroCacheManager --> <!-- 用于缓存AuthenticationInfo -->
  36. <bean id="customShiroCacheManager" class="com.brillilab.ssmdemo.common.shiro.cache.impl.CustomShiroCacheManager">
  37. <property name="shiroCacheManager" ref="jedisShiroCacheManager"/>
  38. </bean>
  39. <!-- shiro 缓存实现,对ShiroCacheManager,我是采用redis的实现 -->
  40. <bean id="jedisShiroCacheManager" class="com.brillilab.ssmdemo.common.shiro.cache.impl.JedisShiroCacheManager">
  41. <property name="jedisManager" ref="jedisManager"/>
  42. </bean>
  43. <!-- 授权 认证 -->
  44. <bean id="userRealm" class="com.brillilab.ssmdemo.common.shiro.realms.UserRealm" >
  45. <property name="cacheManager" ref="customShiroCacheManager"/>
  46. <property name="cachingEnabled" value="false"/>
  47. <property name="authenticationCachingEnabled" value="true"/>
  48. <property name="authenticationCacheName" value="authenticationCache"/>
  49. <property name="authorizationCachingEnabled" value="true"/>
  50. <property name="authorizationCacheName" value="authorizationCache"/>
  51. </bean>
  52. <!-- (三)SessionManager -->
  53. <!-- DefaultWebSessionManager -->
  54. <bean id="customShiroSessionDAO" class="com.brillilab.ssmdemo.common.shiro.session.CustomShiroSessionDAO">
  55. <property name="shiroSessionRepository" ref="jedisShiroSessionRepository"/>
  56. <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
  57. </bean>
  58. <!-- SessionDAO -->
  59. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
  60. <!-- 相隔多久检查一次session的有效性 -->
  61. <property name="sessionValidationInterval" value="180000"/>
  62. <!-- session 有效时间为半小时 (毫秒单位)-->
  63. <property name="globalSessionTimeout" value="180000"/>
  64. <property name="sessionDAO" ref="customShiroSessionDAO"/>
  65. <!-- session 监听,可以多个。 -->
  66. <property name="sessionListeners">
  67. <list>
  68. <ref bean="customSessionListener"/>
  69. </list>
  70. </property>
  71. <!-- 不需要注入sessionValidationScheduler 属性-->
  72. <!--<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>-->
  73. <!-- 是否开启 检测,默认开启 -->
  74. <property name="sessionValidationSchedulerEnabled" value="true"/>
  75. <!-- 是否删除无效的,默认也是开启 -->
  76. <property name="deleteInvalidSessions" value="true"/>
  77. <!-- 会话Cookie模板 -->
  78. <property name="sessionIdCookie" ref="sessionIdCookie"/>
  79. </bean>
  80. <!-- 会话Session ID生成器 -->
  81. <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
  82. <!-- session 创建、删除、查询 -->
  83. <bean id="jedisShiroSessionRepository" class="com.brillilab.ssmdemo.common.shiro.session.JedisShiroSessionRepository" >
  84. <property name="jedisManager" ref="jedisManager"/>
  85. </bean>
  86. <!-- 会话Cookie模板 -->
  87. <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
  88. <!--cookie的name,我故意取名叫xxxxbaidu -->
  89. <constructor-arg value="v_v-s-baidu"/>
  90. <property name="httpOnly" value="true"/>
  91. <!--cookie的有效时间 -->
  92. <property name="maxAge" value="180000"/>
  93. <!-- 配置存储Session Cookie的domain为 一级域名
  94. <property name="domain" value=".itboy.net"/>
  95. -->
  96. </bean>
  97. <!-- custom shiro session listener -->
  98. <bean id="customSessionListener" class="com.brillilab.ssmdemo.common.shiro.listenter.CustomSessionListener">
  99. <property name="shiroSessionRepository" ref="jedisShiroSessionRepository"/>
  100. </bean>
  101. <!-- (四)JedisManager redis缓存管理器(DAO) -->
  102. <bean id="jedisManager" class="com.brillilab.ssmdemo.common.shiro.cache.JedisManager">
  103. <property name="jedisPool" ref="jedisPool"/>
  104. </bean>
  105. <!-- (五)shiro权限过滤器 -->
  106. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  107. <property name="securityManager" ref="securityManager" />
  108. <property name="loginUrl" value="/login" />
  109. <property name="successUrl" value="/index" />
  110. <property name="unauthorizedUrl" value="/login" />
  111. <!-- 过滤器映射 -->
  112. <property name="filterChainDefinitions" >
  113. <value>
  114. /common/** = anon
  115. /login = anon
  116. /index = anon
  117. /user/insert = login,permission
  118. /user/delete = login,permission
  119. /logout = anon
  120. </value>
  121. </property>
  122. <property name="filters">
  123. <util:map>
  124. <entry key="login" value-ref="login"/>
  125. <entry key="role" value-ref="role"/>
  126. <entry key="permission" value-ref="permission"/>
  127. <entry key="logout" value-ref="logout"/>
  128. </util:map>
  129. </property>
  130. </bean>
  131. <!-- 自定义权限过滤器 -->
  132. <bean id="login" class="com.brillilab.ssmdemo.common.shiro.filter.LoginFilter"/>
  133. <bean id="role" class="com.brillilab.ssmdemo.common.shiro.filter.RoleFilter"/>
  134. <bean id="permission" class="com.brillilab.ssmdemo.common.shiro.filter.PermissionFilter"/>
  135. <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
  136. <property name="redirectUrl" value="/index"/>
  137. </bean>
  138. <!-- (六)Shiro生命周期处理器-->
  139. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
  140. </beans>

(2)web.xml的编写


 
 
  1. <!-- ShiroFilter -->
  2. <filter>
  3. <filter-name>shiroFilter </filter-name>
  4. <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class>
  5. </filter>
  6. <filter-mapping>
  7. <filter-name>shiroFilter </filter-name>
  8. <url-pattern>/* </url-pattern>
  9. </filter-mapping>

*注意:shiro的自定义组件全部在com.brillilab.ssmdemo.shiro包中

4.Shiro基础操作的使用示例

以下所有操作均在web情景中进行

(1)登录校验


 
 
  1. @RequestMapping(value = "/login",method = RequestMethod.POST)
  2. public String login(User user, Boolean rememberme, HttpServletRequest request, HttpServletResponse response){
  3. try {
  4. //1.获取认证对象
  5. Subject subject = SecurityUtils.getSubject();
  6. //2.实例化Token对象
  7. String sessionId=request.getRequestedSessionId();
  8. String username=user.getUsername();
  9. String password=user.getPassword();
  10. UsernamePasswordToken token= new UsernamePasswordToken(username,password,rememberme);
  11. //3.进行登录认证
  12. subject.login(token);
  13. } catch (Exception e){
  14. return "error/loginerror";
  15. }
  16. return "redirect:/index";
  17. }

(2)登出操作


 
 
  1. @RequestMapping("/logout")
  2. public String logout(HttpServletRequest request, HttpServletResponse response){
  3. Subject subject = SecurityUtils.getSubject();
  4. subject.logout();
  5. return "redirect:/index";
  6. }

(3)自定义Realm


 
 
  1. public class UserRealm extends AuthorizingRealm {
  2. @Autowired
  3. UserService userService;
  4. @Autowired
  5. RoleService roleService;
  6. @Autowired
  7. PermissionService permissionService;
  8. /**
  9. * 授权信息,用于进行权限认证
  10. */
  11. @Override
  12. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  13. //(1)获得签名, 可做进一步查询
  14. User token= (User) principalCollection.getPrimaryPrincipal();
  15. User user=userService.login(token);
  16. //(2)创建SimpleAuthenticationInfo对象
  17. SimpleAuthorizationInfo info= new SimpleAuthorizationInfo();
  18. //(3)查询角色、权限信息
  19. Set<String> roles = roleService.findRolesByUser(user);
  20. info.setRoles(roles);
  21. Set<String> permissions = permissionService.findPermissionsByUser(user);
  22. info.addStringPermissions(permissions);
  23. return info;
  24. }
  25. /**
  26. * 认证信息,主要针对用户登录,
  27. */
  28. @Override
  29. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  30. //(1)获取登录的token
  31. UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
  32. //(2)获取username和password,调用登录
  33. String username=token.getUsername();
  34. String password= new String(token.getPassword());
  35. User user= new User();
  36. user.setUsername(username);
  37. user.setPassword(password);
  38. User login = userService.login(user);
  39. //(3)登录失败
  40. if ( null==login){
  41. throw new AccountException( "账号或密码不正确!");
  42. }
  43. if (login.getStatus()== 0){
  44. throw new DisabledAccountException( "帐号已经禁止登录!");
  45. }
  46. //(4)登录成功
  47. login.setUpdatetime( new Date());
  48. userService.updateUser(login);
  49. return new SimpleAuthenticationInfo(login,login.getPassword(),login.getUsername());
  50. }
  51. }

(4)权限校验


 
 
  1. Subject subject = SecurityUtils.getSubject();
  2. List< String> roles = Arrays.asList( new String[]{ "admin", "super"});
  3. subject.hasAllRoles(roles);
  4. subject.hasRole( "admin");

(5)JSP页面内容授权

  • 在JSP页面引入Shiro标签ku

    <pre class="has" style="margin-left:0px;" name="code" "hljs.copyCode(event)"><code style="margin-left:0px;" class="hljs swift">&lt;%@ taglib <span class="hljs-keyword">prefix</span>=<span class="hljs-string">"shiro"</span> uri=<span class="hljs-string">"http://shiro.apache.org/tags"</span> %&gt;
    




  • <shiro:guest>标签中的类容在游客访问时显示

  • <pre class="has" style="margin-left:0px;" name="code" "hljs.copyCode(event)"><code style="margin-left:0px;" class="hljs vbscript-html"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="xml"><span class="hljs-comment">&lt;!-- shiro标签测试 --&gt;</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;<span class="hljs-name">shiro:guest</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;/<span class="hljs-name">li</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&lt;/<span class="hljs-attr">shiro:guest</span>&gt;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"></div></div></li></ol></code><div class="hljs-button {2}" data-title="复制"></div></pre>
    </li>
    <li style="margin-left:0px;">
    <p style="margin-left:0px;">&lt;shiro:hasRole name="1"&gt;标签中的内容在用户登录情况下,角色包含name属性值时显示</p>
    
    <pre class="has" style="margin-left:0px;" name="code" "hljs.copyCode(event)"><code style="margin-left:0px;" class="hljs vbscript-html"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">shiro:hasRole</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"1"</span>&gt;</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>管理员<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;/<span class="hljs-name">li</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&lt;/<span class="hljs-attr">shiro:hasRole</span>&gt;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"></div></div></li></ol></code><div class="hljs-button {2}" data-title="复制"></div></pre>
    </li>
    <li style="margin-left:0px;">
    <p style="margin-left:0px;">&lt;shiro:hasPermission name="/user/insert"&gt;标签中的类容在用户登录情况下,权限包含name属性值时显示</p>
    
    <pre class="has" style="margin-left:0px;" name="code" "hljs.copyCode(event)"><code style="margin-left:0px;" class="hljs vbscript-html"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">shiro:hasPermission</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"/user/insert"</span>&gt;</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>能够添加用户<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag">&lt;/<span class="hljs-name">li</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&lt;/<span class="hljs-attr">shiro:hasPermission</span>&gt;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"></div></div></li></ol></code><div class="hljs-button {2}" data-title="复制"></div></pre>
    </li>
    

    5.Shiro自定义权限过滤器

    (1)自定义拦截器的配置

    
     
     
    1. <!-- (五)shiro权限过滤器 -->
    2. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    3. <property name="securityManager" ref="securityManager" />
    4. <property name="loginUrl" value="/login" />
    5. <property name="successUrl" value="/index" />
    6. <property name="unauthorizedUrl" value="/login" />
    7. <!-- 过滤器映射 -->
    8. <property name="filterChainDefinitions" >
    9. <value>
    10. /common/** = anon
    11. /login = anon
    12. /index = anon
    13. /user/insert = login,permission
    14. /user/delete = login,permission
    15. </value>
    16. </property>
    17. <property name="filters">
    18. <util:map>
    19. <entry key="login" value-ref="login"> </entry>
    20. <entry key="role" value-ref="role"> </entry>
    21. </util:map>
    22. </property>
    23. </bean>
    24. <!-- 自定义拦截器 -->
    25. <bean id="login" class="com.brillilab.ssmdemo.common.shiro.filter.LoginFilter"/>
    26. <bean id="role" class="com.brillilab.ssmdemo.common.shiro.filter.RoleFilter"/>
    27. <bean id="permission" class="com.brillilab.ssmdemo.common.shiro.filter.PermissionFilter"/>

    (2)登录过滤器

    1.LoginFilter

    
     
     
    1. public class LoginFilter extends AccessControlFilter {
    2. /**
    3. * 写如何能通过该拦截器的逻辑
    4. */
    5. @Override
    6. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
    7. //(1)获取认证信息
    8. User token = (User)SecurityUtils.getSubject().getPrincipal();
    9. //(2)登录请求直接放行
    10. if( null != token || isLoginRequest(request, response)){
    11. return true;
    12. }
    13. //(3)非登录请求,重定向到登录页面
    14. ResultVo result = ResultVoUtil.failed( "当前用户没有登录!");
    15. WebUtil.jsonOut(response,result);
    16. return false;
    17. }
    18. /**
    19. * isAccessAllowed返回值为fales时经过该方法
    20. */
    21. @Override
    22. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    23. //保存Request和Response 到登录后的链接
    24. saveRequestAndRedirectToLogin(request, response);
    25. return false;
    26. }
    27. }

    (3)权限过滤器

    2.RoleFilter

    
     
     
    1. public class RoleFilter extends AccessControlFilter {
    2. /**
    3. * 写如何能通过该拦截器的逻辑
    4. */
    5. @Override
    6. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object value) throws Exception {
    7. //(1)获取认证实体
    8. Subject subject = getSubject(request, response);
    9. //(2)进行角色校验(角色为"1"能通过)
    10. if (subject.hasAllRoles(Arrays.asList( "1"))){
    11. return true;
    12. }
    13. //(3)未通过角色校验重定向回登录页面
    14. ((HttpServletResponse)response).sendRedirect(request.getServletContext().getContextPath()+ "/login");
    15. return false;
    16. }
    17. /**
    18. * isAccessAllowed返回值为fales时经过该方法
    19. */
    20. @Override
    21. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    22. //(3)未通过角色校验重定向回登录页面
    23. //((HttpServletResponse)response).sendRedirect(request.getServletContext().getContextPath()+"/login");
    24. Subject subject = getSubject(request, response);
    25. if (subject.getPrincipal()== null){
    26. //未登录重定向登录页面
    27. saveRequest(request);
    28. WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+ "/login");
    29. } else {
    30. //已登录重定向未授权错误页面
    31. WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+ "/error/unauthorizerror");
    32. }
    33. return false;
    34. }
    35. }

    3.PermissionFilter

    
     
     
    1. public class PermissionFilter extends AccessControlFilter {
    2. /**
    3. * 写如何能通过该拦截器的逻辑
    4. */
    5. @Override
    6. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
    7. //(1)获取认证实体
    8. Subject subject = getSubject(request,response);
    9. //(2)进行权限校验
    10. //①获取请求url
    11. HttpServletRequest httpRequest=(HttpServletRequest)request;
    12. String url = httpRequest.getRequestURI();
    13. String contextPath = httpRequest.getContextPath();
    14. if (url!= null && url.startsWith(contextPath)){
    15. url = url.replaceFirst(contextPath, "");
    16. }
    17. //②权限校验
    18. if (subject.isPermitted(url)){
    19. return true;
    20. }
    21. return false;
    22. }
    23. /**
    24. * isAccessAllowed返回值为fales时经过该方法
    25. */
    26. @Override
    27. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    28. //(3)未通过权限校验的逻辑
    29. Subject subject = getSubject(request, response);
    30. if (subject.getPrincipal()== null){
    31. //未登录重定向登录页面
    32. saveRequest(request);
    33. WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+ "/login");
    34. } else {
    35. //已登录重定向未授权错误页面
    36. WebUtil.jsonOut(response,ResultVoUtil.failed( "用户未被授权该操作"));
    37. }
    38. return false;
    39. }
    40. }

     

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SSM框架中使用Shiro进行免登录功能的实现可以按照以下步骤进行: 1. 在用户登录成功后,生成一个唯一的标识符,例如UUID,并将其存储到Cookie中。可以使用`HttpServletResponse`对象的`addCookie()`方法来设置Cookie。 2. 将该标识符作为key,用户密码作为value,存储到Redis中。可以使用Redis的客户端库(例如Jedis)来连接Redis服务器并执行存储操作。 3. 在用户访问需要认证的页面时,通过Shiro的过滤器进行权限验证。在Shiro的配置文件中添加相应的过滤器和拦截规则。 4. 创建一个自定义的Shiro Realm,在其中重写`doGetAuthenticationInfo()`方法,用于从Redis中根据Cookie的值获取用户密码,并验证用户身份。 下面是一个简单示例代码: 1. 在登录成功后生成并设置Cookie: ```java // 生成UUID作为标识符 String sessionId = UUID.randomUUID().toString(); // 将sessionId存储到Cookie中 Cookie cookie = new Cookie("sessionId", sessionId); response.addCookie(cookie); // 将sessionId和用户密码存储到Redis中 Jedis jedis = new Jedis("redis_host", redis_port); jedis.set(sessionId, user.getPassword()); jedis.expire(sessionId, expire_time); ``` 2. 在Shiro配置文件中添加过滤器和拦截规则: ```xml <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- ...其他配置... --> <property name="filters"> <map> <!-- ...其他过滤器配置... --> <entry key="authc"> <bean class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <!-- 设置登录页的URL --> <property name="loginUrl" value="/login"/> </bean> </entry> <entry key="user"> <bean class="org.apache.shiro.web.filter.authc.UserFilter"/> </entry> </map> </property> <property name="filterChainDefinitions"> <value> /login = anon /logout = logout /** = user </value> </property> </bean> ``` 3. 创建自定义Shiro Realm并重写`doGetAuthenticationInfo()`方法: ```java public class CustomRealm extends AuthorizingRealm { // ...其他重写的方法... @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { if (!(token instanceof UsernamePasswordToken)) { return null; } UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String sessionId = usernamePasswordToken.getUsername(); // 从Redis中根据sessionId获取用户密码 Jedis jedis = new Jedis("redis_host", redis_port); String password = jedis.get(sessionId); if (password == null) { throw new UnknownAccountException("Invalid session"); } // 返回身份验证信息 return new SimpleAuthenticationInfo(sessionId, password, getName()); } } ``` 以上是一种基本的实现方式,你可以根据具体的业务需求进行适当调整和扩展。同时,请确保在生产环境中对Cookie和Redis的安全性进行合理的加固和保护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值