三方面讲解:
1--基本原理
2-- 从SpringSecurity源码
基本原理如下:
在用户发送认证请求之后,或调用我们之前说过的usernamePasswordAuthenticationFilter这个过滤器,认证成功之后会调用一个服务负责针对每一用户生成一个Token,然后将token写入Cookie与数据库中。当用户再次请求的时候会经过过滤器链中的RemeberMeAuthenticationFilter,通过名字我们也知道这个了过滤器的作用便是读取Cookie中的Token,然后Service会到数据库里查Token是否有记录,如果有记录会调用UserDetailsService然后根据用户名与密码程程认证的信息
ps:RemeberMeAuthenticationFilter是在所有绿色过滤器中排列为倒数第二个。
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
//---------这里是最主要的 转向了 successfulAuthentication方法
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
//---------这个可以从我们对应的图上找到
rememberMeServices.loginSuccess(request, response, authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
//---------然后通过onLoginSuccess 我们可以得知token分别加入到了数据库与cookie中
protected void onLoginSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication successfulAuthentication) {
String username = successfulAuthentication.getName();
logger.debug("Creating new persistent login for user " + username);
PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(
username, generateSeriesData(), generateTokenData(), new Date());
try {
tokenRepository.createNewToken(persistentToken);
addCookie(persistentToken, request, response);
}
catch (Exception e) {
logger.error("Failed to save persistent token ", e);
}
}
//--------下面是我们再次登陆 RememberMeAuthenticationFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//-------------从这得知Authentication在之前没有任何的认证 则或调用autoLogin,
这个方法会从请求中获取cookie,然后用TokenRepository依据cookie中获取的presentedSeries
去从数据库获得相应的信息。获得之后则作出相应的判断 是否存在值 是否过期等
if (SecurityContextHolder.getContext().getAuthentication() == null) {
Authentication rememberMeAuth = rememberMeServices.autoLogin(request,
response);
if (rememberMeAuth != null) {
// Attempt authenticaton via AuthenticationManager
try {
rememberMeAuth = authenticationManager.authenticate(rememberMeAuth);
// Store to SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
……………………………………