shiro认证流程
DeBug启动项目之后自己打一些断点
1 填写form表单之后 点击登录,shiro会帮我们做认证,验证用户的信息是否正确,正确就登录,不正确就重定向到登录页面
2:shiro第一步会进入到MyFormAuthenticationFilter.java 类中的onAccessDenied(ServletRequestrequest,ServletResponse response)方法中
2.1判断是否为登录请求,判断是否为登录提交,如果是,获取HttpServletRequest,根据HttpServletRequest来获取请求参数验证码code和登录类型(如果有单点登录)先判断登录类型,再判断验证码是否正确,具体的看代码
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {//判断是否为登录请求
if (isLoginSubmission(request, response)) {//是否为登录提交请求
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String vercode = httpServletRequest.getParameter("code");//获取验证码
String logtype = httpServletRequest.getParameter("logtype");//获取登录类型(有单点登录的时候)
if (logtype.equals("0")) {//判断登录类型 0为普通登录
if (StringUtil.hasValue(vercode) && !vercode.toLowerCase().equals (httpServletRequest.getSession()
.getAttribute("_code"))) {//判断验证码信息
ResponseResults responseResults = ResponseResults.warn("验证码错误!");
output(response, responseResults);
return false;//中止filter链
}
return executeLogin(request, response);
}
else {
return executeLogin(request, response);//单点登录直接进行登录
}
} else {
return true;
}
} else {
saveRequestAndRedirectToLogin(request, response);
return false;
}
}
3:F7跳出方法,进入自定义Realm(继承了AuthorizingRealm)中的doGetAuthenticationInfo(Authe nticationToken token)方法中,方法的返回值 AuthenticationInfo token中封装了从登录页面传回来的用户名和密码,判断登录类型,普通登录和单点登录的返回方式一样,返回的参数略有不同,
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
ServletRequest request = ((WebSubject)SecurityUtils.getSubject()).getServletRequest();
ServletResponse resp =((WebSubject)SecurityUtils.getSubject()).getServletResponse();
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
String logtype = request.getParameter("logtype");
if (logtype.equals("1")) {//单点登录
String password = new String((char[])token.getCredentials());//获取密码
ResponseResults msg=sysSingleLoginService.identification_cooks((String) token.getPrincipal(), password,httpServletRequest,httpServletResponse);//调用单点登录验证方法
if (Integer.valueOf(msg.get("code").toString())==0) {
String userid=msg.get("msg").toString();//获取用户
HttpSession session = httpServletRequest.getSession();
session.setAttribute("SINGLEUSER",userid);//将用户封装到session中
return new SimpleAuthenticationInfo(userid, "", "");
}
else {
String err=msg.get("msg").toString();
switch(err){
case "-1":
throw new DisabledAccountException();
case "-2":
throw new UnknownAccountException();
case "-3":
throw new IncorrectCredentialsException();
default: throw new AuthenticationException("");
}
}
}
//普通登录
User user = userService.getuUserById((String) token.getPrincipal());
if (null == user) {
throw new UnknownAccountException();
}
if ("0".equals(user.getFlag())) {
throw new DisabledAccountException();
}
return new SimpleAuthenticationInfo(user.getUserId(), user.getUserPassword(), getName());
}
之后进入到RetryLimitHashedCredentialsMatchers类中的doCredentialsMatchers(AuthenticationToke
n token, AuthenticationInfo info)方法中判断密码是否正确,
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
ServletRequest request = ((WebSubject)SecurityUtils.getSubject()).getServletRequest();
String logtype = request.getParameter("logtype");
String username = (String) token.getPrincipal();
// retry count + 1
AtomicInteger retryCount = passwordRetryCache.get(username);
if (retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if (retryCount.incrementAndGet() > 200) {
// if retry count > 5 throw
throw new ExcessiveAttemptsException();
}
logger.info("key=" + (String) info.getPrincipals().getPrimaryPrincipal());
logger.info("user=" + new String((char[]) token.getCredentials()));
logger.info("db=" + info.getCredentials());
logger.info("des=" + ThreeDes.toEncode((String) info.getPrincipals().getPrimaryPrincipal(), new String((char[]) token.getCredentials())));
if (logtype.equals("1")) {//单点登录
String singleuser = request.getParameter("singleuser");
return true;
}
boolean matches = ThreeDes.toEncode((String) info.getPrincipals().getPrimaryPrincipal(), new String((char[]) token.getCredentials())).equals(
info.getCredentials());
if (matches) {//密码匹配
// clear retry count
passwordRetryCache.remove(username);//清空缓存
}
return matches;
}
匹配成功之后最后进入MyFormAuthenticationFilter 类中的onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,ServletResponse response)方法中
将用户的信息封装到session中,保存用户信息,记录登录日志,
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
SysUser sysUser;
String logtype = request.getParameter("logtype");
if (logtype.equals("1")) {
String singleuser = session.getAttribute("SINGLEUSER").toString();
sysUser=sysUserService.getSysUserById(singleuser);
}
else {
sysUser = sysUserService.getSysUserById((String) token.getPrincipal());
}
//session.setMaxInactiveInterval(30 * 60);
session.setAttribute("USERKEY", sysUser.getUserKey());
session.setAttribute("USERID", sysUser.getUserId());
UsernamePasswordToken tokenEx= (UsernamePasswordToken) token;
String pass=String.valueOf(tokenEx.getPassword());
session.setAttribute("USERDEFAULTVALUE", pass.equals("123456"));
session.setAttribute("USERIPARDESS", getIpAddress(httpServletRequest));
sysUser.setLastIp(request.getRemoteAddr());
sysUser.setLastTime(DateUtil.getDateTime());
sysUserService.save(sysUser);
sysLogingLogService.saveLoginLog(sysUser.getUserKey(), sysUser.getUserId(), sysUser.getUserName(), sysUser.getRegionCode(), sysUser.getFacultyCode(), getIpAddress(httpServletRequest));
output(response, ResponseResults.ok());
return false;
}
重在流程走向