RememberMeServices
RememberMeServices
记住我的服务的接口
可以重写实现自己的记住我
public interface RememberMeServices {
//建议 org. springframework. security. authentication. RememberMeAuthenticationToken 在大多数情况下使用它,因为它具有相应的身份验证提供程序。Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);void loginFail(HttpServletRequest request, HttpServletResponse response);void loginSuccess(HttpServletRequest request, HttpServletResponse response,Authentication successfulAuthentication);
}
AbstractRememberMeServices
记住我基类
public abstract class AbstractRememberMeServicesimplements RememberMeServices, InitializingBean, LogoutHandler, MessageSourceAware {
}
- 从请求内获取cookie
- 判断cookie长度是否为0,为0删除cookie
- cookie解码
- 执行autoLoginCookie,返回用户详细信息
- 检查cookie判断是否被禁用
- 创建从 autoLogin 方法返回的最终 Authentication 对象。
在请求中找到 Spring Security 记住我 cookie 并返回其值。
当MaxAge为0时候表示删除cookie
解码 cookie 并使用 “:” 分隔符将其拆分为一组令牌字符串。
由子类实现,整个autoLogin是一个模板方法
返回的最终 Authentication 对象
TokenBasedRememberMeServices
校验过期时间->生成签名并与cookieTokens中进行比较
PersistentTokenBasedRememberMeServices
默认实现InMemory,还提供了JDBC
RememberMeAuthenticationFilter
来看看RememberMe的引用
之前也提到过GenericFilterBean,他是Filte的简单基本实现,不处理这个过滤器仅执行一次
public class RememberMeAuthenticationFilter extends GenericFilterBean implements ApplicationEventPublisherAware {
// 成功处理器private AuthenticationSuccessHandler successHandler;
// 授权管理器private AuthenticationManager authenticationManager;
// 上文提到的记住我服务 private RememberMeServices rememberMeServices;
// 策略类private SecurityContextRepository securityContextRepository = new NullSecurityContextRepository();
}
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {// 不为null,说明已经认证过了if (SecurityContextHolder.getContext().getAuthentication() != null) {this.logger.debug(LogMessage.of(() -> "SecurityContextHolder not populated with remember-me token, as it already contained: '"+ SecurityContextHolder.getContext().getAuthentication() + "'"));chain.doFilter(request, response);return;}Authentication rememberMeAuth = this.rememberMeServices.autoLogin(request, response);if (rememberMeAuth != null) {// Attempt authenticaton via AuthenticationManagertry {// 授权、认证rememberMeAuth = this.authenticationManager.authenticate(rememberMeAuth);// Store to SecurityContextHolder// 重新设置上下文SecurityContext context = SecurityContextHolder.createEmptyContext();context.setAuthentication(rememberMeAuth);// 之前也提及过,默认是threadLoacl SecurityContextHolder.setContext(context); onSuccessfulAuthentication(request, response, rememberMeAuth);this.logger.debug(LogMessage.of(() -> "SecurityContextHolder populated with remember-me token: '"+ SecurityContextHolder.getContext().getAuthentication() + "'"));// 保存securityContextthis.securityContextRepository.saveContext(context, request, response);if (this.eventPublisher != null) {this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(SecurityContextHolder.getContext().getAuthentication(), this.getClass()));}if (this.successHandler != null) {this.successHandler.onAuthenticationSuccess(request, response, rememberMeAuth);return;}}catch (AuthenticationException ex) {this.logger.debug(LogMessage.format("SecurityContextHolder not populated with remember-me token, as AuthenticationManager "+ "rejected Authentication returned by RememberMeServices: '%s'; "+ "invalidating remember-me token", rememberMeAuth),ex);this.rememberMeServices.loginFail(request, response);onUnsuccessfulAuthentication(request, response, ex);}}chain.doFilter(request, response);}
RememberMeAuthenticationToken
指示类可以处理特定的 Authentication 实现,策略模式
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}
RememberMeAuthenticationProvider
RememberMeConfigurer
配置记住我过滤器,核心方法init和configure
这一步可以设置自己的RememberMeService
.and().rememberMe().rememberMeServices(rememberMeServices()) // 设置自动登录时使用rememberServic