1. 程式人生 > >簡單實現Shiro單點登入(自定義Token令牌)

簡單實現Shiro單點登入(自定義Token令牌)

Java程式碼 
  1. /** 
  2.  * 單點登入(如已經登入,則直接跳轉) 
  3.  * @param userCode 登入使用者編碼 
  4.  * @param token 登入令牌,令牌組成:sso金鑰+使用者名稱+日期,進行md5加密,舉例:  
  5.  *      String secretKey = Global.getConfig("shiro.sso.secretKey"); 
  6.  *      String token = Digests.md5(secretKey + userCode + DateUtils.getDate("yyyyMMdd")); 
  7.  * @param url 登入成功後跳轉的url地址。 
  8.  * @param relogin 是否重新登入,需要重新登入傳遞true
     
  9.  * 例如:http://localhost/project/sso/{token}?url=xxx&relogin=true 
  10.  */  
  11. @RequestMapping(value = "sso/{userCode}/{token}")  
  12. public String sso(@PathVariable String userCode, @PathVariable String token,   
  13.         @RequestParam(required=true) String url, String relogin, Model model) {  
  14.     Principal principal = UserUtils.getPrincipal();  
  15.     // 如果已經登入  
  16.     if(principal != null){  
  17.         // 如果設定強制重新登入,則重新登入  
  18.         if (BooleanUtils.toBoolean(relogin)){  
  19.             UserUtils.getSubject().logout();  
  20.         }  
  21.         // 否則,直接跳轉到目標頁  
  22.         else{  
  23.             return "redirect:" + Encodes.urlDecode2(url);  
  24.         }  
  25.     }  
  26.     // 進行單點登入  
  27.     if
     (token != null){  
  28.         UsernamePasswordToken upt = new UsernamePasswordToken();  
  29.         try {  
  30.             upt.setUsername(userCode); // 登入使用者名稱  
  31.             upt.setPassword(token.toCharArray()); // 密碼組成:sso金鑰+使用者名稱+日期,進行md5加密,舉例: Digests.md5(secretKey+username+20150101))  
  32.             upt.setParams(upt.toString()); // 單點登入識別引數,see: AuthorizingRealm.assertCredentialsMatch  
  33.         } catch (Exception ex){  
  34.             if (!ex.getMessage().startsWith("msg:")){  
  35.                 ex = new AuthenticationException("msg:授權令牌錯誤,請聯絡管理員。");  
  36.             }  
  37.             model.addAttribute("exception", ex);  
  38.         }  
  39.         try {  
  40.             UserUtils.getSubject().login(upt);  
  41.             return "redirect:" + Encodes.urlDecode2(url);  
  42.         } catch (AuthenticationException ae) {  
  43.             if (!ae.getMessage().startsWith("msg:")){  
  44.                 ae = new AuthenticationException("msg:授權錯誤,請檢查使用者配置,若不能解決,請聯絡管理員。");  
  45.             }  
  46.             model.addAttribute("exception", ae);  
  47.         }  
  48.     }  
  49.     return "error/403";  
  50. }  

2. 過載org.apache.shiro.realm.AuthorizingRealm類的assertCredentialsMatch方法

Java程式碼 
  1. /** 
  2.  * 認證密碼匹配呼叫方法 
  3.  */  
  4. @Override  
  5. protected void assertCredentialsMatch(AuthenticationToken authcToken,  
  6.         AuthenticationInfo info) throws AuthenticationException {  
  7.     UsernamePasswordToken token = (UsernamePasswordToken) authcToken;  
  8.     // 若單點登入,則使用單點登入授權方法。  
  9.     if (token.toString().equals(token.getParams())){  
  10.         // sso金鑰+使用者名稱+日期,進行md5加密,舉例: Digests.md5(secretKey+username+20150101))  
  11.         String secretKey = Global.getConfig("shiro.sso.secretKey");  
  12.         String password = Digests.md5(secretKey + token.getUsername() + DateUtils.getDate("yyyyMMdd"));  
  13.         if (password.equals(String.valueOf(token.getPassword()))){  
  14.             return;  
  15.         }  
  16.     }  
  17.     super.assertCredentialsMatch(token, info);  
  18. }  

3. 實現Shiro無狀態訪問,如通過傳遞sessionid引數即可實現會話訪問

 這裡需要自定義Shiro的SessionManager類,方法是繼承org.apache.shiro.web.session.mgt.DefaultWebSessionManager類,過載getSessionId方法,如下:

Java程式碼 
  1. public class SessionManager extends DefaultWebSessionManager {  
  2.     public SessionManager() {  
  3.         super();  
  4.     }  
  5.     @Override  
  6.     protected Serializable getSessionId(ServletRequest request, ServletResponse response) {  
  7.         // 如果引數中包含“__sid”引數,則使用此sid會話。 例如:http://localhost/project?__sid=xxx&__cookie=true  
  8.         // 其實這裡還可以使用如下引數:cookie中的session名稱:如:JSESSIONID=xxx,路徑中的 ;JESSIONID=xxx,但建議還是使用 __sid引數。  
  9.         String sid = request.getParameter("__sid");  
  10.         if (StringUtils.isNotBlank(sid)) {  
  11.             // 是否將sid儲存到cookie,瀏覽器模式下使用此引數。  
  12.             if (WebUtils.isTrue(request, "__cookie")){  
  13.                 HttpServletRequest rq = (HttpServletRequest)request;  
  14.                 HttpServletResponse rs = (HttpServletResponse)response;  
  15.                 Cookie template = getSessionIdCookie();  
  16.                 Cookie cookie = new SimpleCookie(template);  
  17.                 cookie.setValue(sid); cookie.saveTo(rq, rs);  
  18.             }  
  19.             // 設定當前session狀態  
  20.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,  
  21.                     ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session來源與url  
  22.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);  
  23.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);  
  24.             return sid;  
  25.         }else{  
  26.             return super.getSessionId(request, response);  
  27.         }  
  28.     }  
  29. }
    http://www.cnblogs.com/coderhuang/p/5897444.html