簡單實現Shiro單點登入(自定義Token令牌)
阿新 • • 發佈:2019-01-06
Java程式碼
- /**
- * 單點登入(如已經登入,則直接跳轉)
- * @param userCode 登入使用者編碼
- * @param token 登入令牌,令牌組成:sso金鑰+使用者名稱+日期,進行md5加密,舉例:
- * String secretKey = Global.getConfig("shiro.sso.secretKey");
- * String token = Digests.md5(secretKey + userCode + DateUtils.getDate("yyyyMMdd"));
- * @param url 登入成功後跳轉的url地址。
- * @param relogin 是否重新登入,需要重新登入傳遞true
- * 例如:http://localhost/project/sso/{token}?url=xxx&relogin=true
- */
- @RequestMapping(value = "sso/{userCode}/{token}")
- public String sso(@PathVariable String userCode, @PathVariable String token,
- @RequestParam(required=true) String url, String relogin, Model model) {
- Principal principal = UserUtils.getPrincipal();
- // 如果已經登入
- if(principal != null){
- // 如果設定強制重新登入,則重新登入
- if (BooleanUtils.toBoolean(relogin)){
- UserUtils.getSubject().logout();
- }
- // 否則,直接跳轉到目標頁
- else{
- return "redirect:" + Encodes.urlDecode2(url);
- }
- }
- // 進行單點登入
- if
- UsernamePasswordToken upt = new UsernamePasswordToken();
- try {
- upt.setUsername(userCode); // 登入使用者名稱
- upt.setPassword(token.toCharArray()); // 密碼組成:sso金鑰+使用者名稱+日期,進行md5加密,舉例: Digests.md5(secretKey+username+20150101))
- upt.setParams(upt.toString()); // 單點登入識別引數,see: AuthorizingRealm.assertCredentialsMatch
- } catch (Exception ex){
- if (!ex.getMessage().startsWith("msg:")){
- ex = new AuthenticationException("msg:授權令牌錯誤,請聯絡管理員。");
- }
- model.addAttribute("exception", ex);
- }
- try {
- UserUtils.getSubject().login(upt);
- return "redirect:" + Encodes.urlDecode2(url);
- } catch (AuthenticationException ae) {
- if (!ae.getMessage().startsWith("msg:")){
- ae = new AuthenticationException("msg:授權錯誤,請檢查使用者配置,若不能解決,請聯絡管理員。");
- }
- model.addAttribute("exception", ae);
- }
- }
- return "error/403";
- }
2. 過載org.apache.shiro.realm.AuthorizingRealm類的assertCredentialsMatch方法
Java程式碼- /**
- * 認證密碼匹配呼叫方法
- */
- @Override
- protected void assertCredentialsMatch(AuthenticationToken authcToken,
- AuthenticationInfo info) throws AuthenticationException {
- UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
- // 若單點登入,則使用單點登入授權方法。
- if (token.toString().equals(token.getParams())){
- // sso金鑰+使用者名稱+日期,進行md5加密,舉例: Digests.md5(secretKey+username+20150101))
- String secretKey = Global.getConfig("shiro.sso.secretKey");
- String password = Digests.md5(secretKey + token.getUsername() + DateUtils.getDate("yyyyMMdd"));
- if (password.equals(String.valueOf(token.getPassword()))){
- return;
- }
- }
- super.assertCredentialsMatch(token, info);
- }
3. 實現Shiro無狀態訪問,如通過傳遞sessionid引數即可實現會話訪問
這裡需要自定義Shiro的SessionManager類,方法是繼承org.apache.shiro.web.session.mgt.DefaultWebSessionManager類,過載getSessionId方法,如下:
Java程式碼- public class SessionManager extends DefaultWebSessionManager {
- public SessionManager() {
- super();
- }
- @Override
- protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
- // 如果引數中包含“__sid”引數,則使用此sid會話。 例如:http://localhost/project?__sid=xxx&__cookie=true
- // 其實這裡還可以使用如下引數:cookie中的session名稱:如:JSESSIONID=xxx,路徑中的 ;JESSIONID=xxx,但建議還是使用 __sid引數。
- String sid = request.getParameter("__sid");
- if (StringUtils.isNotBlank(sid)) {
- // 是否將sid儲存到cookie,瀏覽器模式下使用此引數。
- if (WebUtils.isTrue(request, "__cookie")){
- HttpServletRequest rq = (HttpServletRequest)request;
- HttpServletResponse rs = (HttpServletResponse)response;
- Cookie template = getSessionIdCookie();
- Cookie cookie = new SimpleCookie(template);
- cookie.setValue(sid); cookie.saveTo(rq, rs);
- }
- // 設定當前session狀態
- request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
- ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session來源與url
- request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
- request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
- return sid;
- }else{
- return super.getSessionId(request, response);
- }
- }
- }
http://www.cnblogs.com/coderhuang/p/5897444.html