jeesite登录流程------》
一:
loginIndex.jsp 的登录表单提交------》FormAuthenticationFilter的createToken()方法,目的new UsernamePasswordToken()
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String xx1 = request.getParameter("xx"); if (password==null){ password = ""; } boolean rememberMe = isRememberMe(request); String host = StringUtils.getRemoteAddr((HttpServletRequest)request); String captcha = getCaptcha(request); boolean mobile = isMobileLogin(request); //return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile); return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile,xx1); }
二:
---------------》SystemAuthorizingRealm 的doGetAuthenticationInfo(),这里从上一步的UsernamePasswordToken类中取到表单的用户名,密码等,再从数据库取出用户名,密码进行比较验证
/** * 认证回调函数, 登录时调用 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String xx1 = token.getXx(); int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size(); if (logger.isDebugEnabled()){ logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername()); } // 校验登录验证码 if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){ Session session = UserUtils.getSession(); String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){ throw new AuthenticationException("msg:验证码错误, 请重试."); } } // 校验用户名密码 User user = getSystemService().getUserByLoginName(token.getUsername()); if (user != null) { if (Global.NO.equals(user.getLoginFlag())){ throw new AuthenticationException("msg:该已帐号禁止登录."); } byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16)); return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName()); } else { return null; } }
三:(二)中的验证如果失败,则执行FormAuthenticationFilter的onLoginFailure()方法
/** * 登录失败调用事件 */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { String className = e.getClass().getName(), message = ""; if (IncorrectCredentialsException.class.getName().equals(className) || UnknownAccountException.class.getName().equals(className)){ message = "用户或密码错误, 请重试."; } else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")){ message = StringUtils.replace(e.getMessage(), "msg:", ""); } else{ message = "系统出现点问题,请稍后再试!"; e.printStackTrace(); // 输出到控制台 } request.setAttribute(getFailureKeyAttribute(), className); request.setAttribute(getMessageParam(), message); return true; }
接着执行:LoginController的loginFail()方法
* 登录失败,真正登录的POST请求由Filter完成 */ @RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST) public String loginFail(HttpServletRequest request, HttpServletResponse response, Model model) { /* CookieUtils.setCookie(response, "LOGINED", "false"); */ Principal principal = UserUtils.getPrincipal(); String xx = request.getParameter("xx"); // 如果已经登录,则跳转到管理首页 if(principal != null){ return "redirect:" + adminPath; } String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM); boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM); boolean mobile = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_MOBILE_PARAM); String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME); String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM); //登录失败,设置logined false CookieUtils.setCookie(response, "LOGINED", "false"); if (StringUtils.isBlank(message) || StringUtils.equals(message, "null")){ message = "用户或密码错误, 请重试."; } model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username); model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe); model.addAttribute(FormAuthenticationFilter.DEFAULT_MOBILE_PARAM, mobile); model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception); model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, message); if (logger.isDebugEnabled()){ logger.debug("login fail, active session size: {}, message: {}, exception: {}", sessionDAO.getActiveSessions(false).size(), message, exception); } // 非授权异常,登录失败,验证码加1。 if (!UnauthorizedException.class.getName().equals(exception)){ model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, true, false)); } // 验证失败清空验证码 request.getSession().setAttribute(ValidateCodeServlet.VALIDATE_CODE, IdGen.uuid()); // 如果是手机登录,则返回JSON字符串 if (mobile){ return renderString(response, model); } //return "modules/sys/sysLogin"; model.addAttribute("errormessage", message); return "modules/news/loginIndex"; }
再接着执行:LoginController的login()方法
/** * 管理登录 */ @RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET) public String login(HttpServletRequest request, HttpServletResponse response, Model model) { Principal principal = UserUtils.getPrincipal(); // // 默认页签模式 // String tabmode = CookieUtils.getCookie(request, "tabmode"); // if (tabmode == null){ // CookieUtils.setCookie(response, "tabmode", "1"); // } if (logger.isDebugEnabled()){ logger.debug("login, active session size: {}", sessionDAO.getActiveSessions(false).size()); } // 如果已登录,再次访问主页,则退出原账号。 if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){ CookieUtils.setCookie(response, "LOGINED", "false"); } // 如果已经登录,则跳转到管理首页 if(principal != null && !principal.isMobileLogin()){ return "redirect:" + adminPath; } // String view; // view = "/WEB-INF/views/modules/sys/sysLogin.jsp"; // view = "classpath:"; // view += "jar:file:/D:/GitHub/jeesite/src/main/webapp/WEB-INF/lib/jeesite.jar!"; // view += "/"+getClass().getName().replaceAll("\\.", "/").replace(getClass().getSimpleName(), "")+"view/sysLogin"; // view += ".jsp"; //return "modules/sys/sysLogin"; return "modules/news/loginIndex"; }
四:(二)中的验证如果成功,执行FormAuthenticationFilter的issueSuccessRedirect()方法,
@Override protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception { // Principal p = UserUtils.getPrincipal(); // if (p != null && !p.isMobileLogin()){ WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true); // }else{ // super.issueSuccessRedirect(request, response); // } }
接着执行:LoginController的index()方法
/** * 登录成功,进入管理首页 */ @RequiresPermissions("user") @RequestMapping(value = "${adminPath}") public String index(HttpServletRequest request, HttpServletResponse response,Model model) { String xx = request.getParameter("xx"); CookieUtils.setCookie(response, "LOGINED", "true"); Principal principal = UserUtils.getPrincipal(); // 登录成功后,验证码计算器清零 isValidateCodeLogin(principal.getLoginName(), false, true); if (logger.isDebugEnabled()){ logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size()); } // 如果已登录,再次访问主页,则退出原账号。 if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){ String logined = CookieUtils.getCookie(request, "LOGINED"); if (StringUtils.isBlank(logined) || "false".equals(logined)){ CookieUtils.setCookie(response, "LOGINED", "true"); }else if (StringUtils.equals(logined, "true")){ UserUtils.getSubject().logout(); return "redirect:" + adminPath + "/login"; } } // 如果是手机登录,则返回JSON字符串 if (principal.isMobileLogin()){ if (request.getParameter("login") != null){ return renderString(response, principal); } if (request.getParameter("index") != null){ return "modules/sys/sysIndex"; } return "redirect:" + adminPath + "/login"; } // // 登录成功后,获取上次登录的当前站点ID // UserUtils.putCache("siteId", StringUtils.toLong(CookieUtils.getCookie(request, "siteId"))); // System.out.println("==========================a"); // try { // byte[] bytes = com.thinkgem.jeesite.common.utils.FileUtils.readFileToByteArray( // com.thinkgem.jeesite.common.utils.FileUtils.getFile("c:\\sxt.dmp")); // UserUtils.getSession().setAttribute("kkk", bytes); // UserUtils.getSession().setAttribute("kkk2", bytes); // } catch (Exception e) { // e.printStackTrace(); // } //// for (int i=0; i<1000000; i++){ //// //UserUtils.getSession().setAttribute("a", "a"); //// request.getSession().setAttribute("aaa", "aa"); //// } // System.out.println("==========================b"); /*return "modules/sys/sysIndex";*/ return "redirect:" + "cc/zdh" + "/getZy"; }
总得讲,首先request被formAuthenticationFilter接收到,然后传给createToken函数,该函数从request中取出name and password,然后生成自定义的一个token传给了SystemAuthorizingRealm中的doGetAuthenticationInfo验证。其中SystemAuthorizingRealm内有systemService的实例,该实例含有userDAO能取出数据库中的name and password 接着由这俩密码生成SimpleAuthenticationInfo,再由info中的逻辑来验证。
一般要在表单添加验证参数,如<input name="xx" />
1。先在UsernamePasswordToken 中添加参数
/** * 用户和密码(包含验证码)令牌类 * @author ThinkGem * @version 2013-5-19 */ public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken { private static final long serialVersionUID = 1L; private String captcha; private boolean mobileLogin; //自己加的参数 private String xx; public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha, boolean mobileLogin,String xx) { super(username, password, rememberMe, host); this.captcha = captcha; this.mobileLogin = mobileLogin; this.xx=xx; }
2。FormAuthenticationFilter的createToken()方法中得到参数,传到UsernamePasswordToken中
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String xx1 = request.getParameter("xx"); if (password==null){ password = ""; } boolean rememberMe = isRememberMe(request); String host = StringUtils.getRemoteAddr((HttpServletRequest)request); String captcha = getCaptcha(request); boolean mobile = isMobileLogin(request); //return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile); return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile,xx1); }
3。SystemAuthorizingRealm 的doGetAuthenticationInfo(),这里从上一步的UsernamePasswordToken类中取到表单的参数xx,进行比较验证
/** * 认证回调函数, 登录时调用 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String xx1 = token.getXx(); int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size(); if (logger.isDebugEnabled()){ logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername()); } // 校验登录验证码 if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){ Session session = UserUtils.getSession(); String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){ throw new AuthenticationException("msg:验证码错误, 请重试."); } } // 校验用户名密码 User user = getSystemService().getUserByLoginName(token.getUsername()); if (user != null) { if (Global.NO.equals(user.getLoginFlag())){ throw new AuthenticationException("msg:该已帐号禁止登录."); } byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16)); return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName()); } else { return null; } }
一篇不错的博文:点击打开链接