Springmvc+shiro 你的名字 2022-05-26 11:07 207阅读 0赞 # 第一部分 什么是Apache Shiro # ## 1、什么是 apache shiro : ## Apache Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理 如同 Spring security 一样都是是一个权限安全框架,但是与Spring Security相比,在于他使用了和比较简洁易懂的认证和授权方式。 ## 2、Apache Shiro 的三大核心组件: ## 1、Subject :当前用户的操作 2、SecurityManager:用于管理所有的Subject 3、Realms:用于进行权限信息的验证 Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥 有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。 SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。 Realms:Realms则是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。 ## 3、Authentication 和 Authorization ## 在shiro的用户权限认证过程中其通过两个方法来实现: 1、Authentication:是验证用户身份的过程。 2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。 ## 4、其他组件: ## 除了以上几个组件外,Shiro还有几个其他组件: 1、SessionManager :Shiro为任何应用提供了一个会话编程范式。 2、CacheManager :对Shiro的其他组件提供缓存支持。 ## 5、Shiro 完整架构图: ## **![Center][]** 图片转自:http://kdboy.iteye.com/blog/1154644 # 第二部分 Apache Shiro 整合Spring的Web程序构建 # 1:shiro的配置,通过maven加入shiro相关jar包 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div></td> <td> <div> <div> <code><!-- shiro --> </code> </div> <div> <code> </code> <code><dependency> </code> </div> <div> <code> </code> <code><groupId>org.apache.shiro</groupId> </code> </div> <div> <code> </code> <code><artifactId>shiro-core</artifactId> </code> </div> <div> <code> </code> <code><version></code> <code>1.2</code> <code>.</code> <code>1</code> <code></version> </code> </div> <div> <code> </code> <code></dependency> </code> </div> <div> <code> </code> <code><dependency> </code> </div> <div> <code> </code> <code><groupId>org.apache.shiro</groupId> </code> </div> <div> <code> </code> <code><artifactId>shiro-web</artifactId> </code> </div> <div> <code> </code> <code><version></code> <code>1.2</code> <code>.</code> <code>1</code> <code></version> </code> </div> <div> <code> </code> <code></dependency> </code> </div> <div> <code> </code> <code><dependency> </code> </div> <div> <code> </code> <code><groupId>org.apache.shiro</groupId> </code> </div> <div> <code> </code> <code><artifactId>shiro-ehcache</artifactId> </code> </div> <div> <code> </code> <code><version></code> <code>1.2</code> <code>.</code> <code>1</code> <code></version> </code> </div> <div> <code> </code> <code></dependency> </code> </div> <div> <code> </code> <code><dependency> </code> </div> <div> <code> </code> <code><groupId>org.apache.shiro</groupId> </code> </div> <div> <code> </code> <code><artifactId>shiro-spring</artifactId> </code> </div> <div> <code> </code> <code><version></code> <code>1.2</code> <code>.</code> <code>1</code> <code></version> </code> </div> <div> <code> </code> <code></dependency></code> </div> </div></td> </tr> </tbody> </table> 2 :在web.xml中添加shiro过滤器 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div></td> <td> <div> <div> <code><!-- 配置shiro的核心拦截器 --> </code> </div> <div> <code> </code> <code><filter> </code> </div> <div> <code> </code> <code><filter-name>shiroFilter</filter-name> </code> </div> <div> <code> </code> <code><filter-</code> <code>class</code> <code>>org.springframework.web.filter.DelegatingFilterProxy</filter-</code> <code>class</code> <code>> </code> </div> <div> <code> </code> <code></filter> </code> </div> <div> <code> </code> <code><filter-mapping> </code> </div> <div> <code> </code> <code><filter-name>shiroFilter</filter-name> </code> </div> <div> <code> </code> <code><url-pattern>/admin/*</url-pattern> </code> </div> <div> <code> </code> <code></filter-mapping></code> </div> </div></td> </tr> </tbody> </table> 3: springmvc中对shiro配置 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div> <div> 39 </div> <div> 40 </div> <div> 41 </div> <div> 42 </div> <div> 43 </div> <div> 44 </div> <div> 45 </div> <div> 46 </div> <div> 47 </div> <div> 48 </div> <div> 49 </div> <div> 50 </div> <div> 51 </div> <div> 52 </div> <div> 53 </div> <div> 54 </div> <div> 55 </div> <div> 56 </div> <div> 57 </div> <div> 58 </div> <div> 59 </div> <div> 60 </div> <div> 61 </div> <div> 62 </div> <div> 63 </div> <div> 64 </div> <div> 65 </div> <div> 66 </div> <div> 67 </div> <div> 68 </div> <div> 69 </div> <div> 70 </div> <div> 71 </div> <div> 72 </div> <div> 73 </div> <div> 74 </div> <div> 75 </div> <div> 76 </div> <div> 77 </div> <div> 78 </div> <div> 79 </div> <div> 80 </div> <div> 81 </div> <div> 82 </div> <div> 83 </div> <div> 84 </div> <div> 85 </div> <div> 86 </div> <div> 87 </div> <div> 88 </div> <div> 89 </div> <div> 90 </div> <div> 91 </div> <div> 92 </div> <div> 93 </div> <div> 94 </div> <div> 95 </div> <div> 96 </div> <div> 97 </div> <div> 98 </div> <div> 99 </div> <div> 100 </div> <div> 101 </div> <div> 102 </div> <div> 103 </div> <div> 104 </div> <div> 105 </div> <div> 106 </div> <div> 107 </div> <div> 108 </div> <div> 109 </div> <div> 110 </div> <div> 111 </div></td> <td> <div> <div> <code><beans xmlns=</code> <code>"<a href="http://www.springframework.org/schema/beans" rel="nofollow">http://www.springframework.org/schema/beans</a>"</code> </div> <div> <code> </code> <code>xmlns:xsi=</code> <code>"<a href="http://www.w3.org/2001/XMLSchema-instance" rel="nofollow">http://www.w3.org/2001/XMLSchema-instance</a>"</code> <code>xmlns:mvc=</code> <code>"<a href="http://www.springframework.org/schema/mvc" rel="nofollow">http://www.springframework.org/schema/mvc</a>"</code> </div> <div> <code> </code> <code>xmlns:context=</code> <code>"<a href="http://www.springframework.org/schema/context" rel="nofollow">http://www.springframework.org/schema/context</a>"</code> </div> <div> <code> </code> <code>xmlns:aop=</code> <code>"<a href="http://www.springframework.org/schema/aop" rel="nofollow">http://www.springframework.org/schema/aop</a>"</code> <code>xmlns:tx=</code> <code>"<a href="http://www.springframework.org/schema/tx" rel="nofollow">http://www.springframework.org/schema/tx</a>"</code> </div> <div> <code> </code> <code>xsi:schemaLocation="http:</code> <code>//www.springframework.org/schema/beans </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/beans/spring-beans-3.2.xsd </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/mvc </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/mvc/spring-mvc-3.2.xsd </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/context </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/context/spring-context-3.2.xsd </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/aop </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/aop/spring-aop-3.2.xsd </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/tx </code> </div> <div> <code> </code> <code>http:</code> <code>//www.springframework.org/schema/tx/spring-tx-3.2.xsd "> </code> </div> <div> <code> </code> <code><!-- web.xml中shiro的filter对应的bean --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"shiroFilter"</code> <code>class</code> <code>=</code> <code>"org.apache.shiro.spring.web.ShiroFilterFactoryBean"</code> <code>> </code> </div> <div> <code> </code> <code><!-- 管理器,必须设置 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"securityManager"</code> <code>ref=</code> <code>"securityManager"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 拦截到,跳转到的地址,通过此地址去认证 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"loginUrl"</code> <code>value=</code> <code>"/admin/login.do"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 认证成功统一跳转到/admin/index.</code> <code>do</code> <code>,建议不配置,shiro认证成功自动到上一个请求路径 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"successUrl"</code> <code>value=</code> <code>"/admin/index.do"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"unauthorizedUrl"</code> <code>value=</code> <code>"/refuse.jsp"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 自定义filter,可用来更改默认的表单名称配置 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"filters"</code> <code>> </code> </div> <div> <code> </code> <code><map> </code> </div> <div> <code> </code> <code><!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 --> </code> </div> <div> <code> </code> <code><entry key=</code> <code>"authc"</code> <code>value-ref=</code> <code>"formAuthenticationFilter"</code> <code>/> </code> </div> <div> <code> </code> <code></map> </code> </div> <div> <code> </code> <code></property> </code> </div> <div> <code> </code> <code><property name=</code> <code>"filterChainDefinitions"</code> <code>> </code> </div> <div> <code> </code> <code><value> </code> </div> <div> <code> </code> <code><!-- 对静态资源设置匿名访问 --> </code> </div> <div> <code> </code> <code>/images/** = anon </code> </div> <div> <code> </code> <code>/js/** = anon </code> </div> <div> <code> </code> <code>/styles/** = anon </code> </div> <div> <code> </code> <code><!-- 验证码,可匿名访问 --> </code> </div> <div> <code> </code> <code>/validatecode.jsp = anon </code> </div> <div> <code> </code> <code><!-- 请求 logout.</code> <code>do</code> <code>地址,shiro去清除session --> </code> </div> <div> <code> </code> <code>/admin/logout.</code> <code>do</code> <code>= logout </code> </div> <div> <code> </code> <code><!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 --> </code> </div> <div> <code> </code> <code><!-- /items/queryItems.action = perms[item:query] /items/editItems.action </code> </div> <div> <code> </code> <code>= perms[item:edit] --> </code> </div> <div> <code> </code> <code><!-- 配置记住我或认证通过可以访问的地址 --> </code> </div> <div> <code> </code> <code>/welcome.jsp = user </code> </div> <div> <code> </code> <code>/admin/index.</code> <code>do</code> <code>= user </code> </div> <div> <code> </code> <code><!-- /** = authc 所有url都必须认证通过才可以访问 --> </code> </div> <div> <code> </code> <code>/** = authc </code> </div> <div> <code> </code> <code></value> </code> </div> <div> <code> </code> <code></property> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- securityManager安全管理器 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"securityManager"</code> <code>class</code> <code>=</code> <code>"org.apache.shiro.web.mgt.DefaultWebSecurityManager"</code> <code>> </code> </div> <div> <code> </code> <code><property name=</code> <code>"realm"</code> <code>ref=</code> <code>"customRealm"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 注入缓存管理器 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"cacheManager"</code> <code>ref=</code> <code>"cacheManager"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 注入session管理器 --> </code> </div> <div> <code> </code> <code><!-- <property name=</code> <code>"sessionManager"</code> <code>ref=</code> <code>"sessionManager"</code> <code>/> --> </code> </div> <div> <code> </code> <code><!-- 记住我 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"rememberMeManager"</code> <code>ref=</code> <code>"rememberMeManager"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 自定义realm --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"customRealm"</code> <code>class</code> <code>=</code> <code>"com.zhijianj.stucheck.shiro.CustomRealm"</code> <code>> </code> </div> <div> <code> </code> <code><!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 --> </code> </div> <div> <code> </code> <code><!-- <property name=</code> <code>"credentialsMatcher"</code> <code>ref=</code> <code>"credentialsMatcher"</code> <code>/> --> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 凭证匹配器 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"credentialsMatcher"</code> </div> <div> <code> </code> <code>class</code> <code>=</code> <code>"org.apache.shiro.authc.credential.HashedCredentialsMatcher"</code> <code>> </code> </div> <div> <code> </code> <code><!-- 选用MD5散列算法 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"hashAlgorithmName"</code> <code>value=</code> <code>"md5"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 进行一次加密 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"hashIterations"</code> <code>value=</code> <code>"1"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 自定义form认证过虑器 --> </code> </div> <div> <code> </code> <code><!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 --> </code> </div> <div> <code> </code> <code><!-- 可通过此配置,判断验证码 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"formAuthenticationFilter"</code> </div> <div> <code> </code> <code>class</code> <code>=</code> <code>"com.zhijianj.stucheck.shiro.CustomFormAuthenticationFilter "</code> <code>> </code> </div> <div> <code> </code> <code><!-- 表单中账号的input名称,默认为username --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"usernameParam"</code> <code>value=</code> <code>"username"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 表单中密码的input名称,默认为password --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"passwordParam"</code> <code>value=</code> <code>"password"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 记住我input的名称,默认为rememberMe --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"rememberMeParam"</code> <code>value=</code> <code>"rememberMe"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 会话管理器 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"sessionManager"</code> </div> <div> <code> </code> <code>class</code> <code>=</code> <code>"org.apache.shiro.web.session.mgt.DefaultWebSessionManager"</code> <code>> </code> </div> <div> <code> </code> <code><!-- session的失效时长,单位毫秒 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"globalSessionTimeout"</code> <code>value=</code> <code>"600000"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 删除失效的session --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"deleteInvalidSessions"</code> <code>value=</code> <code>"true"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 缓存管理器 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"cacheManager"</code> <code>class</code> <code>=</code> <code>"org.apache.shiro.cache.ehcache.EhCacheManager"</code> <code>> </code> </div> <div> <code> </code> <code><property name=</code> <code>"cacheManagerConfigFile"</code> <code>value=</code> <code>"classpath:shiro-ehcache.xml"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"rememberMeManager"</code> <code>class</code> <code>=</code> <code>"org.apache.shiro.web.mgt.CookieRememberMeManager"</code> <code>> </code> </div> <div> <code> </code> <code><property name=</code> <code>"cookie"</code> <code>ref=</code> <code>"rememberMeCookie"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code> </code> <code><!-- 记住我cookie --> </code> </div> <div> <code> </code> <code><bean id=</code> <code>"rememberMeCookie"</code> <code>class</code> <code>=</code> <code>"org.apache.shiro.web.servlet.SimpleCookie"</code> <code>> </code> </div> <div> <code> </code> <code><!-- rememberMe是cookie的名字 --> </code> </div> <div> <code> </code> <code><constructor-arg value=</code> <code>"rememberMe"</code> <code>/> </code> </div> <div> <code> </code> <code><!-- 记住我cookie生效时间</code> <code>30</code> <code>天 --> </code> </div> <div> <code> </code> <code><property name=</code> <code>"maxAge"</code> <code>value=</code> <code>"2592000"</code> <code>/> </code> </div> <div> <code> </code> <code></bean> </code> </div> <div> <code></beans></code> </div> </div></td> </tr> </tbody> </table> 4 :自定义Realm编码 <table> <tbody> <tr> <td> </td> <td> <div> <div> <code><code>public</code> <code>class</code> <code>CustomRealm </code><code>extends</code> <code>AuthorizingRealm { </code></code> </div> <div> <code> </code> <code>// 设置realm的名称 </code> </div> <div> <code> </code> <code>@Override</code> </div> <div> <code> </code> <code>public</code> <code>void</code> <code>setName(String name) { </code> </div> <div> <code> </code> <code>super</code> <code>.setName(</code> <code>"customRealm"</code> <code>); </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>@Autowired</code> </div> <div> <code> </code> <code>private</code> <code>AdminUserService adminUserService; </code> </div> <div> <code> </code> <code>/** </code> </div> <div> <code> </code> <code>* 认证 </code> </div> <div> <code> </code> <code>*/</code> </div> <div> <code> </code> <code>@Override</code> </div> <div> <code> </code> <code>protected</code> <code>AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) </code> <code>throws</code> <code>AuthenticationException { </code> </div> <div> <code> </code> <code>// token中包含用户输入的用户名和密码 </code> </div> <div> <code> </code> <code>// 第一步从token中取出用户名 </code> </div> <div> <code> </code> <code>String userName = (String) token.getPrincipal(); </code> </div> <div> <code> </code> <code>// 第二步:根据用户输入的userCode从数据库查询 </code> </div> <div> <code> </code> <code>TAdminUser adminUser = adminUserService.getAdminUserByUserName(userName); </code> </div> <div> <code> </code> <code>// 如果查询不到返回null </code> </div> <div> <code> </code> <code>if</code> <code>(adminUser == </code> <code>null</code> <code>) { </code> <code>// </code> </div> <div> <code> </code> <code>return</code> <code>null</code> <code>; </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>// 获取数据库中的密码 </code> </div> <div> <code> </code> <code>String password = adminUser.getPassword(); </code> </div> <div> <code> </code> <code>/** </code> </div> <div> <code> </code> <code>* 认证的用户,正确的密码 </code> </div> <div> <code> </code> <code>*/</code> </div> <div> <code> </code> <code>AuthenticationInfo authcInfo = </code> <code>new</code> <code>SimpleAuthenticationInfo(adminUser, password, </code> <code>this</code> <code>.getName()); </code> </div> <div> <code> </code> <code>//MD5 加密+加盐+多次加密 </code> </div> <div> <code>//<span style="color:#ff0000;">SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(adminUser, password,ByteSource.Util.bytes(salt), this.getName());</span> </code> </div> <div> <code> </code> <code>return</code> <code>authcInfo; </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>/** </code> </div> <div> <code> </code> <code>* 授权,只有成功通过<span style="font-family: Arial, Helvetica, sans-serif;">doGetAuthenticationInfo方法的认证后才会执行。</span> </code> </div> <div> <code> </code> <code>*/</code> </div> <div> <code> </code> <code>@Override</code> </div> <div> <code> </code> <code>protected</code> <code>AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { </code> </div> <div> <code> </code> <code>// 从 principals获取主身份信息 </code> </div> <div> <code> </code> <code>// 将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型), </code> </div> <div> <code> </code> <code>TAdminUser activeUser = (TAdminUser) principals.getPrimaryPrincipal(); </code> </div> <div> <code> </code> <code>// 根据身份信息获取权限信息 </code> </div> <div> <code> </code> <code>// 从数据库获取到权限数据 </code> </div> <div> <code> </code> <code>TAdminRole adminRoles = adminUserService.getAdminRoles(activeUser); </code> </div> <div> <code> </code> <code>// 单独定一个集合对象 </code> </div> <div> <code> </code> <code>List<String> permissions = </code> <code>new</code> <code>ArrayList<String>(); </code> </div> <div> <code> </code> <code>if</code> <code>(adminRoles != </code> <code>null</code> <code>) { </code> </div> <div> <code> </code> <code>permissions.add(adminRoles.getRoleKey()); </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>// 查到权限数据,返回授权信息(要包括 上边的permissions) </code> </div> <div> <code> </code> <code>SimpleAuthorizationInfo simpleAuthorizationInfo = </code> <code>new</code> <code>SimpleAuthorizationInfo(); </code> </div> <div> <code> </code> <code>// 将上边查询到授权信息填充到simpleAuthorizationInfo对象中 </code> </div> <div> <code> </code> <code>simpleAuthorizationInfo.addStringPermissions(permissions); </code> </div> <div> <code> </code> <code>return</code> <code>simpleAuthorizationInfo; </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>// 清除缓存 </code> </div> <div> <code> </code> <code>public</code> <code>void</code> <code>clearCached() { </code> </div> <div> <code> </code> <code>PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); </code> </div> <div> <code> </code> <code>super</code> <code>.clearCache(principals); </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code>}</code> </div> </div></td> </tr> </tbody> </table> <table> <tbody> <tr> <td> <div> <div> <code></code> </div> </div></td> </tr> </tbody> </table> 5 缓存配置 ehcache.xml代码如下: <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div></td> <td> <div> <div> <code><ehcache updateCheck=</code> <code>"false"</code> <code>name=</code> <code>"shiroCache"</code> <code>> </code> </div> <div> <code> </code> <code><defaultCache </code> </div> <div> <code> </code> <code>maxElementsInMemory=</code> <code>"10000"</code> </div> <div> <code> </code> <code>eternal=</code> <code>"false"</code> </div> <div> <code> </code> <code>timeToIdleSeconds=</code> <code>"120"</code> </div> <div> <code> </code> <code>timeToLiveSeconds=</code> <code>"120"</code> </div> <div> <code> </code> <code>overflowToDisk=</code> <code>"false"</code> </div> <div> <code> </code> <code>diskPersistent=</code> <code>"false"</code> </div> <div> <code> </code> <code>diskExpiryThreadIntervalSeconds=</code> <code>"120"</code> </div> <div> <code> </code> <code>/> </code> </div> <div> <code></ehcache></code> </div> </div></td> </tr> </tbody> </table> 通过使用ehache中就避免第次都向服务器发送权限授权(doGetAuthorizationInfo)的请求。 6.自定义表单编码过滤器 CustomFormAuthenticationFilter代码,认证之前调用,可用于验证码校验 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div></td> <td> <div> <div> <code>public</code> <code>class</code> <code>CustomFormAuthenticationFilter </code> <code>extends</code> <code>FormAuthenticationFilter { </code> </div> <div> <code> </code> <code>// 原FormAuthenticationFilter的认证方法 </code> </div> <div> <code> </code> <code>@Override</code> </div> <div> <code> </code> <code>protected</code> <code>boolean</code> <code>onAccessDenied(ServletRequest request, ServletResponse response) </code> <code>throws</code> <code>Exception { </code> </div> <div> <code> </code> <code>// 在这里进行验证码的校验 </code> </div> <div> <code> </code> </div> <div> <code> </code> <code>// 从session获取正确验证码 </code> </div> <div> <code> </code> <code>HttpServletRequest httpServletRequest = (HttpServletRequest) request; </code> </div> <div> <code> </code> <code>HttpSession session = httpServletRequest.getSession(); </code> </div> <div> <code> </code> <code>// 取出session的验证码(正确的验证码) </code> </div> <div> <code> </code> <code>String validateCode = (String) session.getAttribute(</code> <code>"validateCode"</code> <code>); </code> </div> <div> <code> </code> <code>// 取出页面的验证码 </code> </div> <div> <code> </code> <code>// 输入的验证和session中的验证进行对比 </code> </div> <div> <code> </code> <code>String randomcode = httpServletRequest.getParameter(</code> <code>"randomcode"</code> <code>); </code> </div> <div> <code> </code> <code>if</code> <code>(randomcode != </code> <code>null</code> <code>&& validateCode != </code> <code>null</code> <code>&& !randomcode.equals(validateCode)) { </code> </div> <div> <code> </code> <code>// 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中 </code> </div> <div> <code> </code> <code>httpServletRequest.setAttribute(</code> <code>"shiroLoginFailure"</code> <code>, </code> <code>"randomCodeError"</code> <code>); </code> </div> <div> <code> </code> <code>// 拒绝访问,不再校验账号和密码 </code> </div> <div> <code> </code> <code>return</code> <code>true</code> <code>; </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>return</code> <code>super</code> <code>.onAccessDenied(request, response); </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code>}</code> </div> </div></td> </tr> </tbody> </table> 在此符上验证码jsp界面的代码 validatecode.jsp <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div> <div> 39 </div> <div> 40 </div> <div> 41 </div> <div> 42 </div> <div> 43 </div> <div> 44 </div> <div> 45 </div> <div> 46 </div></td> <td> <div> <div> <code><%@ page language=</code> <code>"java"</code> <code>contentType=</code> <code>"text/html; charset=UTF-8"</code> </div> <div> <code> </code> <code>pageEncoding=</code> <code>"UTF-8"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.util.Random"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.io.OutputStream"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.awt.Color"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.awt.Font"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.awt.Graphics"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"java.awt.image.BufferedImage"</code> <code>%> </code> </div> <div> <code><%@ page </code> <code>import</code> <code>=</code> <code>"javax.imageio.ImageIO"</code> <code>%> </code> </div> <div> <code><% </code> </div> <div> <code> </code> <code>int</code> <code>width = </code> <code>60</code> <code>; </code> </div> <div> <code> </code> <code>int</code> <code>height = </code> <code>32</code> <code>; </code> </div> <div> <code> </code> <code>//create the image </code> </div> <div> <code> </code> <code>BufferedImage image = </code> <code>new</code> <code>BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); </code> </div> <div> <code> </code> <code>Graphics g = image.getGraphics(); </code> </div> <div> <code> </code> <code>// set the background color </code> </div> <div> <code> </code> <code>g.setColor(</code> <code>new</code> <code>Color(</code> <code>0xDCDCDC</code> <code>)); </code> </div> <div> <code> </code> <code>g.fillRect(</code> <code>0</code> <code>, </code> <code>0</code> <code>, width, height); </code> </div> <div> <code> </code> <code>// draw the border </code> </div> <div> <code> </code> <code>g.setColor(Color.black); </code> </div> <div> <code> </code> <code>g.drawRect(</code> <code>0</code> <code>, </code> <code>0</code> <code>, width - </code> <code>1</code> <code>, height - </code> <code>1</code> <code>); </code> </div> <div> <code> </code> <code>// create a random instance to generate the codes </code> </div> <div> <code> </code> <code>Random rdm = </code> <code>new</code> <code>Random(); </code> </div> <div> <code> </code> <code>String hash1 = Integer.toHexString(rdm.nextInt()); </code> </div> <div> <code> </code> <code>// make some confusion </code> </div> <div> <code> </code> <code>for</code> <code>(</code> <code>int</code> <code>i = </code> <code>0</code> <code>; i < </code> <code>50</code> <code>; i++) { </code> </div> <div> <code> </code> <code>int</code> <code>x = rdm.nextInt(width); </code> </div> <div> <code> </code> <code>int</code> <code>y = rdm.nextInt(height); </code> </div> <div> <code> </code> <code>g.drawOval(x, y, </code> <code>0</code> <code>, </code> <code>0</code> <code>); </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>// generate a random code </code> </div> <div> <code> </code> <code>String capstr = hash1.substring(</code> <code>0</code> <code>, </code> <code>4</code> <code>); </code> </div> <div> <code> </code> <code>//将生成的验证码存入session </code> </div> <div> <code> </code> <code>session.setAttribute(</code> <code>"validateCode"</code> <code>, capstr); </code> </div> <div> <code> </code> <code>g.setColor(</code> <code>new</code> <code>Color(</code> <code>0</code> <code>, </code> <code>100</code> <code>, </code> <code>0</code> <code>)); </code> </div> <div> <code> </code> <code>g.setFont(</code> <code>new</code> <code>Font(</code> <code>"Candara"</code> <code>, Font.BOLD, </code> <code>24</code> <code>)); </code> </div> <div> <code> </code> <code>g.drawString(capstr, </code> <code>8</code> <code>, </code> <code>24</code> <code>); </code> </div> <div> <code> </code> <code>g.dispose(); </code> </div> <div> <code> </code> <code>//输出图片 </code> </div> <div> <code> </code> <code>response.setContentType(</code> <code>"image/jpeg"</code> <code>); </code> </div> <div> <code> </code> <code>out.clear(); </code> </div> <div> <code> </code> <code>out = pageContext.pushBody(); </code> </div> <div> <code> </code> <code>OutputStream strm = response.getOutputStream(); </code> </div> <div> <code> </code> <code>ImageIO.write(image, </code> <code>"jpeg"</code> <code>, strm); </code> </div> <div> <code> </code> <code>strm.close(); </code> </div> <div> <code>%></code> </div> </div></td> </tr> </tbody> </table> 7.登录控制器方法 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div></td> <td> <div> <div> <code>/** </code> </div> <div> <code> </code> <code>* 到登录界面 </code> </div> <div> <code> </code> <code>* </code> </div> <div> <code> </code> <code>* @return </code> </div> <div> <code> </code> <code>* @throws Exception </code> </div> <div> <code> </code> <code>*/</code> </div> <div> <code>@RequestMapping</code> <code>(</code> <code>"login.do"</code> <code>) </code> </div> <div> <code>public</code> <code>String adminPage(HttpServletRequest request) </code> <code>throws</code> <code>Exception { </code> </div> <div> <code> </code> <code>// 如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名 </code> </div> <div> <code> </code> <code>String exceptionClassName = (String) request.getAttribute(</code> <code>"shiroLoginFailure"</code> <code>); </code> </div> <div> <code> </code> <code>// 根据shiro返回的异常类路径判断,抛出指定异常信息 </code> </div> <div> <code> </code> <code>if</code> <code>(exceptionClassName != </code> <code>null</code> <code>) { </code> </div> <div> <code> </code> <code>if</code> <code>(UnknownAccountException.</code> <code>class</code> <code>.getName().equals(exceptionClassName)) { </code> </div> <div> <code> </code> <code>// 最终会抛给异常处理器 </code> </div> <div> <code> </code> <code>throw</code> <code>new</code> <code>CustomJsonException(</code> <code>"账号不存在"</code> <code>); </code> </div> <div> <code> </code> <code>} </code> <code>else</code> <code>if</code> <code>(IncorrectCredentialsException.</code> <code>class</code> <code>.getName().equals(exceptionClassName)) { </code> </div> <div> <code> </code> <code>throw</code> <code>new</code> <code>CustomJsonException(</code> <code>"用户名/密码错误"</code> <code>); </code> </div> <div> <code> </code> <code>} </code> <code>else</code> <code>if</code> <code>(</code> <code>"randomCodeError"</code> <code>.equals(exceptionClassName)) { </code> </div> <div> <code> </code> <code>throw</code> <code>new</code> <code>CustomJsonException(</code> <code>"验证码错误 "</code> <code>); </code> </div> <div> <code> </code> <code>} </code> <code>else</code> <code>{ </code> </div> <div> <code> </code> <code>throw</code> <code>new</code> <code>Exception();</code> <code>// 最终在异常处理器生成未知错误 </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>} </code> </div> <div> <code> </code> <code>// 此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径 </code> </div> <div> <code> </code> <code>// 登陆失败还到login页面 </code> </div> <div> <code> </code> <code>return</code> <code>"admin/login"</code> <code>; </code> </div> <div> <code>}</code> </div> </div></td> </tr> </tbody> </table> 8.用户回显Controller 当用户登录认证成功后,CustomRealm在调用完doGetAuthenticationInfo时,通过 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div></td> <td> <div> <div> <code>AuthenticationInfo authcInfo = </code> <code>new</code> <code>SimpleAuthenticationInfo(adminUser, password, </code> <code>this</code> <code>.getName()); </code> </div> <div> <code> </code> <code>return</code> <code>authcInfo;</code> </div> </div></td> </tr> </tbody> </table> SimpleAuthenticationInfo构造参数的第一个参数传入一个用户的对象,之后,可通过Subject subject = SecurityUtils.getSubject();中的subject.getPrincipal()获取到此对象。所以需要回显用户信息时,我这样调用的 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div></td> <td> <div> <div> <code>@RequestMapping</code> <code>(</code> <code>"index.do"</code> <code>) </code> </div> <div> <code>public</code> <code>String index(Model model) { </code> </div> <div> <code> </code> <code>//从shiro的session中取activeUser </code> </div> <div> <code> </code> <code>Subject subject = SecurityUtils.getSubject(); </code> </div> <div> <code> </code> <code>//取身份信息 </code> </div> <div> <code> </code> <code>TAdminUser adminUser = (TAdminUser) subject.getPrincipal(); </code> </div> <div> <code> </code> <code>//通过model传到页面 </code> </div> <div> <code> </code> <code>model.addAttribute(</code> <code>"adminUser"</code> <code>, adminUser); </code> </div> <div> <code> </code> <code>return</code> <code>"admin/index"</code> <code>; </code> </div> <div> <code>}</code> </div> </div></td> </tr> </tbody> </table> 9.在jsp页面中控制权限 先引入shiro的头文件 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div></td> <td> <div> <div> <code><!-- shiro头引入 --> </code> </div> <div> <code><%@ taglib uri=</code> <code>"<a href="http://shiro.apache.org/tags" rel="nofollow">http://shiro.apache.org/tags</a>"</code> <code>prefix=</code> <code>"shiro"</code> <code>%></code> </div> </div></td> </tr> </tbody> </table> 采用shiro标签对权限进行处理 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div></td> <td> <div> <div> <code><!-- 有curd权限才显示修改链接,没有该 权限不显示,相当 于</code> <code>if</code> <code>(hasPermission(curd)) --> </code> </div> <div> <code> </code> <code><shiro:hasPermission name=</code> <code>"curd"</code> <code>> </code> </div> <div> <code> </code> <code><BR /> </code> </div> <div> <code> </code> <code>我拥有超级的增删改查权限额 </code> </div> <div> <code> </code> <code></shiro:hasPermission></code> </div> </div></td> </tr> </tbody> </table> 10.在Controller控制权限 通过@RequiresPermissions注解,指定执行此controller中某个请求方法需要的权限 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div></td> <td> <div> <div> <code>@RequestMapping</code> <code>(</code> <code>"/queryInfo.do"</code> <code>) </code> </div> <div> <code> </code> <code>@RequiresPermissions</code> <code>(</code> <code>"q"</code> <code>)</code> <code>//执行需要"q"权限 </code> </div> <div> <code> </code> <code>public</code> <code>ModelAndView queryItems(HttpServletRequest request) </code> <code>throws</code> <code>Exception { }</code> </div> </div></td> </tr> </tbody> </table> 11.MD5加密加盐处理 这里以修改密码为例,通过获取新的密码(明文)后通过MD5加密+加盐+3次加密为例 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div></td> <td> <div> <div> <code>@RequestMapping</code> <code>(</code> <code>"updatePassword.do"</code> <code>) </code> </div> <div> <code> </code> <code>@ResponseBody</code> </div> <div> <code> </code> <code>public</code> <code>String updateAdminUserPassword(String newPassword) { </code> </div> <div> <code> </code> <code>// 从shiro的session中取activeUser </code> </div> <div> <code> </code> <code>Subject subject = SecurityUtils.getSubject(); </code> </div> <div> <code> </code> <code>// 取身份信息 </code> </div> <div> <code> </code> <code>TAdminUser adminUser = (TAdminUser) subject.getPrincipal(); </code> </div> <div> <code> </code> <code>// 生成salt,随机生成 </code> </div> <div> <code> </code> <code>SecureRandomNumberGenerator secureRandomNumberGenerator = </code> <code>new</code> <code>SecureRandomNumberGenerator(); </code> </div> <div> <code> </code> <code>String salt = secureRandomNumberGenerator.nextBytes().toHex(); </code> </div> <div> <code> </code> <code>Md5Hash md5 = </code> <code>new</code> <code>Md5Hash(newPassword, salt, </code> <code>3</code> <code>); </code> </div> <div> <code> </code> <code>String newMd5Password = md5.toHex(); </code> </div> <div> <code> </code> <code>// 设置新密码 </code> </div> <div> <code> </code> <code>adminUser.setPassword(newMd5Password); </code> </div> <div> <code> </code> <code>// 设置盐 </code> </div> <div> <code> </code> <code>adminUser.setSalt(salt); </code> </div> <div> <code> </code> <code>adminUserService.updateAdminUserPassword(adminUser); </code> </div> <div> <code> </code> <code>return</code> <code>newPassword; </code> </div> <div> <code> </code> <code>}</code> </div> </div></td> </tr> </tbody> </table> <table style="border-spacing:0px;border:1px solid #C0C0C0;width:977px;margin:0px;padding:0px;background:none;float:none;height:auto;line-height:1.1em;vertical-align:baseline;font-family:Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;font-size:12px;min-height:auto;"> <tbody style="margin:0px;padding:0px;background:none;float:none;height:auto;line-height:1.1em;vertical-align:baseline;width:auto;min-height:auto;"> <tr style="margin:0px;padding:0px;background:none;border-top:0px;float:none;height:auto;line-height:1.1em;vertical-align:baseline;width:auto;min-height:auto;"> <td style="padding:3px;border-color:#C0C0C0;border-collapse:collapse;margin:0px;background:none;float:none;height:auto;line-height:1.1em;vertical-align:baseline;width:auto;font-family:Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;font-size:12px;min-height:auto;"> <div style="margin:0px;padding:0px;background:none;border:0px;float:none;height:auto;line-height:1.1em;vertical-align:baseline;width:auto;min-height:auto;"> <div style="margin:0px;padding:0px 1em;background-image:none;border:0px;float:none;height:auto;line-height:1.8em;vertical-align:baseline;width:auto;min-height:auto;white-space:nowrap;"> <code style="margin:0px;padding:0px;background:none;border:0px;float:none;height:auto;line-height:1.8em;vertical-align:baseline;width:auto;font-family:Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;min-height:auto;white-space:nowrap;color:rgb(0,0,0);"></code> </div> </div></td> </tr> </tbody> </table> [Center]: /images/20220526/8f755f17405b424799f2dfb620ef0c53.png
还没有评论,来说两句吧...