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 AbstractRememberMeServices
implements 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 AuthenticationManager
try {
// 授权、认证
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() + "'"));
// 保存securityContext
this.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