最近项目需求研究免登录进入jeesite系统,于是对jeesite的登录逻辑进行了研究。
@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;
}
return "modules/sys/sysLogin";
}
public static Principal getPrincipal(){
try{
Subject subject = SecurityUtils.getSubject();
Principal principal = (Principal)subject.getPrincipal();
if (principal != null){
return principal;
}
// subject.logout();
}catch (UnavailableSecurityManagerException e) {
}catch (InvalidSessionException e){
}
return null;
}
public static Subject getSubject() {
/* 54*/ Subject subject = ThreadContext.getSubject();
/* 55*/ if (subject == null) {
/* 56*/ subject = (new org.apache.shiro.subject.Subject.Builder()).buildSubject();
/* 57*/ ThreadContext.bind(subject);
}
/* 59*/ return subject;
}
首先从UserUtils获取Principal,然后Principal是由Subject强转而来的,Subject由SecurityUtils获取的,具体代码在上面,当系统登录成功的时候ThreadContext会存储Subject信息,所以上面才可以获取到。当登录超时或未登录时,ThreadContext获取不到Subject会重新新建个subject并bind到ThreadContext中。系统根据Principal中的信息判断当前用户是否登录过。
jeeste登录页面是sysLogin.jsp。主要就是个form表单提交
在spring-context-shiro.xml配置了安全认证过滤器执行formAuthenticationFilter
根据请求信息创建token然后传给SystemAuthorizingRealm中的doGetAuthenticationInfo进行认证
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
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);
}
/**
* 认证回调函数, 登录时调用
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
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;
}
}
doGetAuthenticationInfo会根据token中的信息生成SimpleAuthenticationInfo,交给info认证。
return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
public void merge(AuthenticationInfo info) {
/* 194*/ if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty())
/* 195*/ return;
/* 198*/ if (principals == null) {
/* 199*/ principals = info.getPrincipals();
} else {
/* 201*/ if (!(principals instanceof MutablePrincipalCollection))
/* 202*/ principals = new SimplePrincipalCollection(principals);
/* 204*/ ((MutablePrincipalCollection) principals).addAll(info.getPrincipals());
}
/* 213*/ if (credentialsSalt == null && (info instanceof SaltedAuthenticationInfo))
/* 214*/ credentialsSalt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();
/* 217*/ Object thisCredentials = getCredentials();
/* 218*/ Object otherCredentials = info.getCredentials();
/* 220*/ if (otherCredentials == null)
/* 221*/ return;
/* 224*/ if (thisCredentials == null) {
/* 225*/ credentials = otherCredentials;
/* 226*/ return;
}
/* 229*/ if (!(thisCredentials instanceof Collection)) {
/* 230*/ Set newSet = new HashSet();
/* 231*/ newSet.add(thisCredentials);
/* 232*/ setCredentials(newSet);
}
/* 236*/ Collection credentialCollection = (Collection) getCredentials();
/* 237*/ if (otherCredentials instanceof Collection)
/* 238*/ credentialCollection.addAll((Collection) otherCredentials);
/* 240*/ else
/* 240*/ credentialCollection.add(otherCredentials);
}
public boolean equals(Object o) {
/* 253*/ if (this == o)
/* 253*/ return true;
/* 254*/ if (!(o instanceof SimpleAuthenticationInfo))
/* 254*/ return false;
/* 256*/ SimpleAuthenticationInfo that = (SimpleAuthenticationInfo) o;
/* 259*/ return principals == null ? that.principals == null : principals.equals(that.principals);
}
如果认证失败会执行LoginController中的loginFail方法,并且返回登录页面
/**
* 登录失败,真正登录的POST请求由Filter完成
*/
@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)
public String loginFail(HttpServletRequest request, HttpServletResponse response, Model model) {
Principal principal = UserUtils.getPrincipal();
// 如果已经登录,则跳转到管理首页
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);
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";
}
如果登录成功会进行LoginController中的index方法,进入管理页面。
@RequiresPermissions("user")
@RequestMapping(value = "${adminPath}")
public String index(HttpServletRequest request, HttpServletResponse response) {
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";
}
还有些ssm的内容大家应该都知道。