简单实现Shiro单点登录(自定义Token令牌)

1. MVC Controller 映射 sso 方法。 Java代码简单实现Shiro单点登录(自定义Token令牌)
文章图片

  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 = "https://www.it610.com/article/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代码简单实现Shiro单点登录(自定义Token令牌)
文章图片
  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方法,如下:
【简单实现Shiro单点登录(自定义Token令牌)】
Java代码简单实现Shiro单点登录(自定义Token令牌)
文章图片
  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. }

    推荐阅读