SecurityContext.class
当前线程关联的最小安全信息,提供Authentication的get/set方法
SecurityContextHolder.class
SecurityContext的持有器
// 全部委托给策略类public static void setContext(SecurityContext context) {strategy.setContext(context);}public static SecurityContext getContext() {return strategy.getContext();}public static void clearContext() {strategy.clearContext();}
SecurityContextHolderStrategy.class
用于针对线程存储安全上下文信息的策略。
核心实现类ThreadLocalSecurityContextHolderStrategy
ThreadLocalSecurityContextHolderStrategy.class
基于ThreadLocal 的实现SecurityContextHolderStrategy。
回到SecurityContextHolder.class方法
static {initialize();}private static void initialize() {initializeStrategy();initializeCount++;}private static void initializeStrategy() {if (MODE_PRE_INITIALIZED.equals(strategyName)) {Assert.state(strategy != null, "When using " + MODE_PRE_INITIALIZED+ ", setContextHolderStrategy must be called with the fully constructed strategy");return;}// 默认的话就是上文提到的ThreadLocalSecurityContextHolderStrategyif (!StringUtils.hasText(strategyName)) {// Set defaultstrategyName = MODE_THREADLOCAL;}if (strategyName.equals(MODE_THREADLOCAL)) {strategy = new ThreadLocalSecurityContextHolderStrategy();return;}if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {strategy = new InheritableThreadLocalSecurityContextHolderStrategy();return;}if (strategyName.equals(MODE_GLOBAL)) {strategy = new GlobalSecurityContextHolderStrategy();return;}// Try to load a custom strategytry {Class<?> clazz = Class.forName(strategyName);Constructor<?> customStrategy = clazz.getConstructor();strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();}catch (Exception ex) {ReflectionUtils.handleReflectionException(ex);}}
SecurityContextRepository.class
用于在请求之间持久保存的策略 SecurityContext
可以通过redis实现单点登录问题
public interface SecurityContextRepository {// 废弃@DeprecatedSecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);default Supplier<SecurityContext> loadContext(HttpServletRequest request) {return SingletonSupplier.of(() -> loadContext(new HttpRequestResponseHolder(request, null)));}void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response);boolean containsContext(HttpServletRequest request);}
SecurityContextHolderFilter.class
使用 获取 SecurityContextRepository SecurityContext 并将其设置在 SecurityContextHolder上的 的 。javax.servlet.Filter这与 类似SecurityContextPersistenceFilter,只是必须显式调用 来SecurityContextRepository.saveContext(SecurityContext, HttpServletRequest, HttpServletResponse)保存 SecurityContext.这提高了效率,并通过允许不同的身份验证机制单独选择是否应保留身份验证来提供更好的灵活性。
public class SecurityContextHolderFilter extends OncePerRequestFilter {private final SecurityContextRepository securityContextRepository;private boolean shouldNotFilterErrorDispatch;/*** Creates a new instance.* @param securityContextRepository the repository to use. Cannot be null.*/public SecurityContextHolderFilter(SecurityContextRepository securityContextRepository) {Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");this.securityContextRepository = securityContextRepository;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {SecurityContext securityContext = this.securityContextRepository.loadContext(request).get();try {SecurityContextHolder.setContext(securityContext);filterChain.doFilter(request, response);}finally {SecurityContextHolder.clearContext();}}@Overrideprotected boolean shouldNotFilterErrorDispatch() {return this.shouldNotFilterErrorDispatch;}public void setShouldNotFilterErrorDispatch(boolean shouldNotFilterErrorDispatch) {this.shouldNotFilterErrorDispatch = shouldNotFilterErrorDispatch;}}
OncePerRequestFilter .class
每次请求只执行一次filter
SecurityContextConfigurer.class
@Override@SuppressWarnings("unchecked")public void configure(H http) {SecurityContextRepository securityContextRepository = getSecurityContextRepository();if (this.requireExplicitSave) {SecurityContextHolderFilter securityContextHolderFilter = postProcess(new SecurityContextHolderFilter(securityContextRepository));http.addFilter(securityContextHolderFilter);}else {// 由框架帮你去构建filterSecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(securityContextRepository);SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)? sessionManagement.getSessionCreationPolicy() : null;if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {securityContextFilter.setForceEagerSessionCreation(true);http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));}securityContextFilter = postProcess(securityContextFilter);http.addFilter(securityContextFilter);}}