shiro + mybatis+ spring (只用shiro的密码校验和并发剔除)——不用权限之类

http://blog.csdn.net/changliangwl/article/details/51455833

 

shiro + mybatis+ spring (只用shiro的密码校验和并发剔除)——不用权限之类

标签: shirojavamybatisspring
分类:
  1. </pre>          shiro 很强大,但往往项目不可能大改造,往往只需要部分功能,比如用到验证码,加密,还有就是同一个账户在两个地方登录,剔除第一个登录者,本文只提供思路和部 分代码,<p></p><p></p><p>自定义实现ream,< /p><p></p><pre name="code" class="java">package com.shiro.shiro.realm;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import org.apache.shiro.authc.*;  
  7. import org.apache.shiro.authz.AuthorizationInfo;  
  8. import org.apache.shiro.authz.SimpleAuthorizationInfo;  
  9. import org.apache.shiro.realm.AuthorizingRealm;  
  10. import org.apache.shiro.subject.PrincipalCollection;  
  11. import org.apache.shiro.util.ByteSource;  
  12. import org.springframework.beans.factory.annotation.Autowired;  
  13.   
  14. import com.shiro.model.User;  
  15. import com.shiro.service.UserService;  
  16.   
  17.   
  18. public class UserRealm extends AuthorizingRealm {  
  19.   
  20.     @Autowired  
  21.     private UserService userService;  
  22.     //获取授权信息  
  23.     @Override  
  24.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
  25.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
  26.      <span style="font-size:18px;">   <span style="color:#ff0000;"><strong>Set<String>  set =new HashSet<String>();  
  27.         set.add("*:*:*");</strong></span>  
  28.         <span style="color:#ff0000;"><strong>authorizationInfo.setRoles(set);  
  29.         authorizationInfo.setStringPermissions(set);  
  30.         return authorizationInfo;</strong></span></span>  
  31.     }  
  32.    //获取身份验证信息  
  33.     @Override  
  34.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
  35.   
  36.         String username = (String)token.getPrincipal();  
  37.   
  38.         User user = userService.findByUsername(username);  
  39.   
  40.         if(user == null) {  
  41.             throw new UnknownAccountException();//没找到帐号  
  42.         }  
  43.   
  44.         if(Boolean.TRUE.equals(user.getLocked())) {  
  45.             throw new LockedAccountException(); //帐号锁定  
  46.         }  
  47.   
  48.         //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现  
  49.         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(  
  50.                 user.getUsername(), //用户名  
  51.                 user.getPassword(), //密码  
  52.                 ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt  
  53.                 getName()  //realm name  
  54.         );  
  55.         return authenticationInfo;  
  56.     }  
  57.   
  58.     @Override  
  59.     public void clearCachedAuthorizationInfo(PrincipalCollection principals) {  
  60.         super.clearCachedAuthorizationInfo(principals);  
  61.     }  
  62.   
  63.     @Override  
  64.     public void clearCachedAuthenticationInfo(PrincipalCollection principals) {  
  65.         super.clearCachedAuthenticationInfo(principals);  
  66.     }  
  67.   
  68.     @Override  
  69.     public void clearCache(PrincipalCollection principals) {  
  70.         super.clearCache(principals);  
  71.     }  
  72.   
  73.     public void clearAllCachedAuthorizationInfo() {  
  74.         getAuthorizationCache().clear();  
  75.     }  
  76.   
  77.     public void clearAllCachedAuthenticationInfo() {  
  78.         getAuthenticationCache().clear();  
  79.     }  
  80.   
  81.     public void clearAllCache() {  
  82.         clearAllCachedAuthenticationInfo();  
  83.         clearAllCachedAuthorizationInfo();  
  84.     }  
  85.   
  86. }  

  1. 只要在<pre name="code" class="java">doGetAuthorizationInfo方法体里授权所有资源所有角色就好了  
  1. </pre><pre name="code" class="java">  
  1. 剔除功能  
  1. </pre><pre name="code" class="java"><pre name="code" class="java">package com.shiro.shiro.filter;  
  2.   
  3. import org.apache.shiro.cache.Cache;  
  4. import org.apache.shiro.cache.CacheManager;  
  5. import org.apache.shiro.session.Session;  
  6. import org.apache.shiro.session.mgt.DefaultSessionKey;  
  7. import org.apache.shiro.session.mgt.SessionManager;  
  8. import org.apache.shiro.subject.Subject;  
  9. import org.apache.shiro.web.filter.AccessControlFilter;  
  10. import org.apache.shiro.web.util.WebUtils;  
  11.   
  12. import javax.servlet.ServletRequest;  
  13. import javax.servlet.ServletResponse;  
  14. import java.io.Serializable;  
  15. import java.util.Deque;  
  16. import java.util.LinkedList;  
  17.   
  18. /** 
  19.  * 并发剔除 
  20.  */  
  21. public class KickoutSessionControlFilter extends AccessControlFilter {  
  22.   
  23.     private String kickoutUrl; //踢出后到的地址  
  24.     private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户  
  25.     private int maxSession = 1; //同一个帐号最大会话数 默认1  
  26.   
  27.     private SessionManager sessionManager;  
  28.     private Cache<String, Deque<Serializable>> cache;  
  29.   
  30.     public void setKickoutUrl(String kickoutUrl) {  
  31.         this.kickoutUrl = kickoutUrl;  
  32.     }  
  33.   
  34.     public void setKickoutAfter(boolean kickoutAfter) {  
  35.         this.kickoutAfter = kickoutAfter;  
  36.     }  
  37.   
  38.     public void setMaxSession(int maxSession) {  
  39.         this.maxSession = maxSession;  
  40.     }  
  41.   
  42.     public void setSessionManager(SessionManager sessionManager) {  
  43.         this.sessionManager = sessionManager;  
  44.     }  
  45.   
  46.     public void setCacheManager(CacheManager cacheManager) {  
  47.         this.cache = cacheManager.getCache("shiro-kickout-session");  
  48.     }  
  49.   
  50.     @Override  
  51.     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {  
  52.         return false;  
  53.     }  
  54.   
  55.     @Override  
  56.     protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {  
  57.         Subject subject = getSubject(request, response);  
  58.         if(!subject.isAuthenticated() && !subject.isRemembered()) {//未授权且非remember   
  59.             //如果没有登录,直接进行之后的流程  
  60.             return true;  
  61.         }  
  62.   
  63.         Session session = subject.getSession();  
  64.         String username = (String) subject.getPrincipal();  
  65.         Serializable sessionId = session.getId();  
  66.   
  67.         //TODO 同步控制  
  68.         Deque<Serializable> deque = cache.get(username);  
  69.         if(deque == null) {  
  70.             deque = new LinkedList<Serializable>();  
  71.             cache.put(username, deque);  
  72.         }  
  73.   
  74.         //如果队列里没有此sessionId,且用户没有被踢出;放入队列  
  75.         if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {  
  76.             deque.push(sessionId);  
  77.         }  
  78.   
  79.         //如果队列里的sessionId数超出最大会话数,开始踢人  
  80.         while(deque.size() > maxSession) {  
  81.             Serializable kickoutSessionId = null;  
  82.             if(kickoutAfter) { //如果踢出后者  
  83.                 kickoutSessionId = deque.removeFirst();  
  84.             } else { //否则踢出前者  
  85.                 kickoutSessionId = deque.removeLast();  
  86.             }  
  87.             try {  
  88.                 Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));  
  89.                 if(kickoutSession != null) {  
  90.                     //设置会话的kickout属性表示踢出了  
  91.                     kickoutSession.setAttribute("kickout", true);  
  92.                 }  
  93.             } catch (Exception e) {//ignore exception  
  94.             }  
  95.         }  
  96.   
  97.         //如果被踢出了,直接退出,重定向到踢出后的地址  
  98.         if (session.getAttribute("kickout") != null) {  
  99.             //会话被踢出了  
  100.             try {  
  101.                 subject.logout();//这里走的shiro的退出  
  102.             } catch (Exception e) { //ignore  
  103.             }  
  104.             saveRequest(request);  
  105.             WebUtils.issueRedirect(request, response, kickoutUrl);  
  106.             return false;  
  107.         }  
  108.   
  109.         return true;  
  110.     }  
  111. }  

此处用到了缓存,当然可以自己实现,把session存到数据库中然后判断操作
  1. </pre><pre name="code" class="java">再看下部分配置文件  
  1. </pre><pre name="code" class="java">  
  1. <pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:util="http://www.springframework.org/schema/util"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  6.        xsi:schemaLocation="  
  7.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd  
  9.        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">  
  10.     <!-- 缓存管理器 -->  
  11.     <bean id="cacheManager" class="com.shiro.spring.cache.SpringCacheManagerWrapper">  
  12.         <property name="cacheManager" ref="springCacheManager"/>  
  13.     </bean>  
  14.     <!-- 凭证匹配器 -->  
  15.     <bean id="credentialsMatcher" class="com.shiro.shiro.credentials.CredentialsMatcher">  
  16.         <property name="hashAlgorithmName" value="md5"/>  
  17.         <property name="hashIterations" value="2"/>  
  18.         <property name="storedCredentialsHexEncoded" value="true"/>  
  19.     </bean>  
  20.     <!-- Realm实现 -->  
  21.     <bean id="userRealm" class="com.shiro.shiro.realm.UserRealm">  
  22.         <property name="credentialsMatcher" ref="credentialsMatcher"/>  
  23.         <property name="cachingEnabled" value="false"/>  
  24.     </bean>  
  25.     <!-- 会话ID生成器 -->  
  26.     <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>  
  27.     <!-- 会话Cookie模板 maxAge=-1表示浏览器关闭时失效此Cookie-->  
  28.     <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">  
  29.         <constructor-arg value="sid"/>  
  30.         <property name="httpOnly" value="true"/>  
  31.         <property name="maxAge" value="-1"/>  
  32.     </bean>  
  33.     <!-- 会话DAO -->  
  34.     <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">  
  35.         <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>  
  36.         <property name="sessionIdGenerator" ref="sessionIdGenerator"/>  
  37.     </bean>  
  38.     <!-- 会话验证调度器 -->  
  39.     <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">  
  40.         <property name="sessionValidationInterval" value="1800000"/>  
  41.         <property name="sessionManager" ref="sessionManager"/>  
  42.     </bean>  
  43.     <!-- 会话管理器 -->  
  44.     <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">  
  45.         <property name="globalSessionTimeout" value="1800000"/>  
  46.         <property name="deleteInvalidSessions" value="true"/>  
  47.         <property name="sessionValidationSchedulerEnabled" value="true"/>  
  48.         <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>  
  49.         <property name="sessionDAO" ref="sessionDAO"/>  
  50.         <property name="sessionIdCookieEnabled" value="true"/>  
  51.         <property name="sessionIdCookie" ref="sessionIdCookie"/>  
  52.     </bean>  
  53.     <!-- 安全管理器 -->  
  54.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
  55.         <property name="realm" ref="userRealm"/>  
  56.         <property name="sessionManager" ref="sessionManager"/>  
  57.         <property name="cacheManager" ref="cacheManager"/>  
  58.     </bean>  
  59.       
  60.     <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->  
  61.     <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
  62.         <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>  
  63.         <property name="arguments" ref="securityManager"/>  
  64.     </bean>  
  65.   
  66.     <!-- 基于Form表单的身份验证过滤器 -->  
  67. <strong>    <bean id="authcFilter" class="com.shiro.shiro.filter.MyFormAuthenticationFilter">  
  68.         <property name="usernameParam" value="username"/>  
  69.         <property name="passwordParam" value="password"/>  
  70.         <property name="failureKeyAttribute" value="shiroLoginFailure"/>  
  71.     </bean>  
  72.       
  73.      <bean id="validateFilter" class="com.shiro.shiro.filter.ValidateFilter">  
  74.         <property name="verificationAbled" value="true"/>  
  75.         <property name="verificationParam" value="verificationParam"/>  
  76.         <property name="failureKeyAttribute" value="shiroLoginFailure"/>  
  77.     </bean></strong>  
  78.        <!-- Shiro的Web过滤器 -->  
  79.     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
  80.         <property name="securityManager" ref="securityManager"/>  
  81.         <property name="loginUrl" value="/login"/>  
  82.         <property name="filters">  
  83.             <util:map>  
  84.                 <entry key="authc" value-ref="<strong>authcFilter</strong>"/>  
  85.                 <entry key="sysUser" value-ref="sysUserFilter"/>  
  86.                 <entry key="validateFilter" value-ref="<strong>validateFilter</strong>"/>  
  87.                 <entry key="kickout" value-ref="<strong>kickoutSessionControlFilter</strong>"/>  
  88.             </util:map>  
  89.         </property>  
  90.         <property name="filterChainDefinitions">  
  91.             <value>  
  92.                  /login = <strong>validateFilter</strong>,authc  
  93.                  /logout = logout  
  94.                 /authenticated = authc  
  95.                 /** = <strong>kickout</strong>,user,sysUser  
  96.             </value>  
  97.         </property>  
  98.     </bean>  
  99.       
  100.     <!-- currenuser  -->  
  101.     <bean id="sysUserFilter" class="com.shiro.shiro.filter.SysUserFilter"/>  
  102.     <!-- 并发踢出   
  103.             kickoutAfter:是否踢出后来登录的,默认是false   
  104.             kickoutUrl:被踢出后重定向到的地址  
  105.             maxSession:同一个用户最大的会话数,默认1  
  106.      -->  
  107.     <bean id="kickoutSessionControlFilter" class="com.shiro.shiro.filter.KickoutSessionControlFilter">  
  108.         <property name="cacheManager" ref="cacheManager"/>  
  109.         <property name="sessionManager" ref="sessionManager"/>  
  110.         <property name="kickoutAfter" value="false"/>  
  111.         <property name="maxSession" value="2"/>  
  112.         <property name="kickoutUrl" value="/login?kickout=1"/>  
  113.     </bean>  
  114.     <!-- Shiro生命周期处理器-->  
  115.     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
  116.       
  117. </beans>  


  1. </pre><pre name="code" class="java">自定义的  
  1. </pre><pre name="code" class="java"><pre name="code" class="java">package com.shiro.shiro.filter;  
  2.   
  3. import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;  
  4.   
  5. import javax.servlet.ServletRequest;  
  6. import javax.servlet.ServletResponse;  
  7.   
  8. /** 
  9.  * 自定义shiro FormAuthenticationFilter 表单过滤器 
  10.  * @author changliang 
  11.  * 
  12.  */  
  13. public class MyFormAuthenticationFilter extends FormAuthenticationFilter {  
  14.     /** 
  15.      * 授权是否失败 
  16.      */  
  17.     @Override  
  18.     protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {  
  19.         if(request.getAttribute(getFailureKeyAttribute()) != null) {  
  20.             return true;  
  21.         }  
  22.         return super.onAccessDenied(request, response, mappedValue);  
  23.     }  
  24. }  
  1. </pre>密码校验<pre>  
  1. <pre name="code" class="java">package com.shiro.shiro.filter;  
  2.   
  3. import org.apache.shiro.web.filter.AccessControlFilter;  
  4. import org.apache.shiro.web.util.WebUtils;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6.   
  7. import com.shiro.service.UserService;  
  8.   
  9. import javax.servlet.ServletRequest;  
  10. import javax.servlet.ServletResponse;  
  11. import javax.servlet.http.HttpServletRequest;  
  12.   
  13. /** 
  14.  * 验证码过滤器 
  15.  */  
  16. public class ValidateFilter extends AccessControlFilter {  
  17.       
  18.     @SuppressWarnings("unused")  
  19.     @Autowired  
  20.     private UserService userService;  
  21.   
  22.     private boolean verificationAbled = true;                //是否开启验证码支持  
  23.   
  24.     @SuppressWarnings("unused")  
  25.     private String verificationParam = "verificationParam";  //前台提交的验证码参数名  
  26.   
  27.     private String failureKeyAttribute = "shiroLoginFailure"; //验证码验证失败后存储到的属性名  
  28.       
  29.      
  30.     public void setVerificationAbled(boolean verificationAbled) {  
  31.         this.verificationAbled = verificationAbled;  
  32.     }  
  33.   
  34.     public void setVerificationParam(String verificationParam) {  
  35.         this.verificationParam = verificationParam;  
  36.     }  
  37.   
  38.     public void setFailureKeyAttribute(String failureKeyAttribute) {  
  39.         this.failureKeyAttribute = failureKeyAttribute;  
  40.     }  
  41.   
  42.     @Override  
  43.     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {  
  44.         //1、设置验证码是否开启属性,页面可以根据该属性来决定是否显示验证码  
  45.         request.setAttribute("verificationAbled", verificationAbled);  
  46.   
  47.         HttpServletRequest httpServletRequest = WebUtils.toHttp(request);  
  48.         //2、判断验证码是否禁用 或不是表单提交(允许访问)  
  49.         if (verificationAbled == false || !"post".equalsIgnoreCase(httpServletRequest.getMethod())) {  
  50.             return true;  
  51.         }  
  52.        <span style="color:#ff0000;"><strong> //3、此时是表单提交,验证验证码是否正确  
  53.         //TODO 增加自己的验证码校验  
  54.         //return  userService.verification(verificationParam);  
  55.         return true;</strong></span>  
  56.     }  
  57.     @Override  
  58.     protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {  
  59.         //如果验证码失败了,存储失败key属性  
  60.         //在LoginController里过滤用到  
  61.         request.setAttribute(failureKeyAttribute, "<span style="color:#ff0000;">verification.error</span>");  
  62.         return true;  
  63.     }  
  64. }  



处理器
  1. </pre><pre name="code" class="java"><pre name="code" class="java">package com.shiro.controller;  
  2.   
  3. import org.apache.shiro.authc.IncorrectCredentialsException;  
  4. import org.apache.shiro.authc.UnknownAccountException;  
  5. import org.springframework.stereotype.Controller;  
  6. import org.springframework.ui.Model;  
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8.   
  9. import javax.servlet.http.HttpServletRequest;  
  10. /** 
  11.  * 常见错误: 
  12.  *  subject.login() 
  13.      * DisabledAccountException(禁用的帐号)、 
  14.      * LockedAccountException(锁定的帐号)、 
  15.      * UnknownAccountException(错误的帐号)、 
  16.      * ExcessiveAttemptsException(登录失败次数过多)、 
  17.      * IncorrectCredentialsException (错误的凭证)、 
  18.      * ExpiredCredentialsException(过期的凭证) 
  19.  * @author changliang 
  20.  * 
  21.  */  
  22. @Controller  
  23. public class LoginController {  
  24.   
  25.     @RequestMapping(value = "/login"    )  
  26.     public String showLoginForm(HttpServletRequest req, Model model) {  
  27.         String exceptionClassName = (String)req.getAttribute("shiroLoginFailure");  
  28.         String error = null;  
  29.         if(UnknownAccountException.class.getName().equals(exceptionClassName)) {  
  30.             error = "用户名/密码错误";  
  31.         } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {  
  32.             error = "用户名/密码错误";//错误的凭证  
  33.         }else if("<span style="color:#ff0000;">verification.error</span>".equals(exceptionClassName)) {  
  34.             error = "验证码错误";  
  35.         } else if(exceptionClassName != null) {  
  36.             error = "其他错误:" + exceptionClassName;  
  37.         }  
  38.         model.addAttribute("error", error);  
  39.         return "login";  
  40.     }  
  41.   
  42.   
  43. }  

参考 :http://jinnianshilongnian.iteye.com/blog/2049092

  1. </pre><pre name="code" class="java">  
  1. </pre><pre name="code" class="java">  
  1. </pre><pre name="code" class="java">  
  1. </pre><pre name="code" class="java">  
  1. </pre>  
 
posted @ 2016-06-23 08:22  zouhao510  阅读(442)  评论(0编辑  收藏  举报