# 概述

  • SpringSecurity是一个有效、高度定制化的认证与访问控制框架;
  • SpringSecurity是一个致力于为java应用提供认证与授权能力的框架;

# 主体框架构成

  • cas: 基于cas的客户端认证能力
  • crypto: 加解密能力
  • jwt: Json Web Tokens,客户端存储能力
  • oauth2: oauth2三方授权及单点的能力
  • web: 与web应用集成的能力
  • ldap: Light Directory Access Protocol,轻量级目录访问协议,LDAP统一认证服务能力
  • openid: 去中心化的数字身份识别系统认证能力

# 运行时序

springSecurity时序 springSecurity时序 springSecurity时序 springSecurity时序

# 主要官方过滤器说明

# 无条件过滤器

名称 作用 能否阻断 后置处理
ChannelProcessingFilter 确保通过所需的通道传递web请求
ConcurrentSessionFilter 并发会话处理包所需的筛选器;
实现session的日期更新;
检查会话是否过期,是则删除,并广播事件;
进行登出操作;
WebAsyncManagerIntegrationFilter 提供SecurityContext与springWeb的WebAsyncManager之间的集成 不能
SecurityContextPersistenceFilter 在请求之前,从配置的SecurityContextRepository中获取相应信息填充SecurityHolder;
请求完成后,清除holder并将其存储;
不能
HeaderWriterFilter 向当前响应添加响应头。可用于添加启用浏览器保护的某些响应头。像X-Frame-Options,X-XSS-Protection和X-Content-Type-Options。 不能
CorsFilter 处理跨域的预检请求
CsrfFilter 进行跨域请求伪造攻击防护
X509AuthenticationFilter X509证书认证
RequestCacheAwareFilter 如果当前请求被缓存过,则进行还原 不能
SecurityContextHolderAwareRequestFilter 针对ServletRequest进行一次包装,使得request具有更加丰富的API 不能
JaasApiIntegrationFilter jaasApi集成过滤器
RememberMeAuthenticationFilter 记住我过滤器 不能
AnonymousAuthenticationFilter 匿名认证过滤器 不能
OAuth2AuthorizationCodeGrantFilter OAuth2授权码授权过滤器 不能
SessionManagementFilter 会话管理过滤器
ExceptionTranslationFilter 异常转换过滤器 不能
FilterSecurityInterceptor 过滤器拦截(授权)过滤器
SwitchUserFilter 切换用户过滤器

# 条件过滤器

名称 作用 条件 阻断 后置
LogoutFilter 登出处理过滤器 路径匹配
OAuth2AuthorizationRequestRedirectFilter 引导oauth2的授权码以及隐式授权码模式重定向到授权服务器的授权端点 路径匹配
CasAuthenticationFilter Cas(服务端)登录的过滤器 路径匹配
OAuth2LoginAuthenticationFilter OAuth2(服务端)登陆的过滤器 路径匹配
UsernamePasswordAuthenticationFilter 表单登录认证过滤器 路径匹配
OpenIDAuthenticationFilter openID认证过滤器 路径匹配
DefaultLoginPageGeneratingFilter 默认登陆页生成过滤器 路径匹配
DefaultLogoutPageGeneratingFilter 默认登出页生成过滤器 路径匹配
DigestAuthenticationFilter http摘要认证过滤器 请求头匹配
BearerTokenAuthenticationFilter OAuth2访问令牌认证过滤器 请求头匹配
BasicAuthenticationFilter http基本令牌认证过滤器 请求头匹配

# SpringSecurityWeb全解析

# 与Spring环境的结合方式

/*xxx: EnableWebSecurity也是sping3开始便有的特性*/
public @interface EnableWebSecurity {
    /*xxx: webSecurity可以打开配置说明,默认关闭*/
    boolean debug() default false;
}
@Configuration
/*xxx: spring-security的默认配置项,可以自动配置*/
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    private WebSecurity webSecurity;
    
    /*xxx: 默认情况下,采用该配置*/
    private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;

    @Autowired(required = false)
    public void setFilterChainProxySecurityConfigurer(
            ObjectPostProcessor<Object> objectPostProcessor,
           /*xxx: 收集SecurityConfigurer,一般来说,单个SecurityConfigurer就代表一条过滤链*/
           List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
            throws Exception {
        webSecurity = objectPostProcessor
                .postProcess(new WebSecurity(objectPostProcessor));
        /*xxx: 省略其它抽象...*/
        for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
            webSecurity.apply(webSecurityConfigurer);
        }
        this.webSecurityConfigurers = webSecurityConfigurers;
    }

    /*xxx: 这个bean的名称,也是有门道的,不能轻易变更*/
    @Bean("springSecurityFilterChain")
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        /*xxx: 在没有配置的情况下,采用默认配置*/
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();
    }
}
/*xxx: 该类位由spring-web项目提供实现*/
/*xxx: springSecurity与web集成时候的入口类*/
public class DelegatingFilterProxy extends GenericFilterBean {
    /*xxx: 代理的filter类*/
    private volatile Filter delegate;

    public DelegatingFilterProxy(Filter delegate) {
        Assert.notNull(delegate, "Delegate Filter must not be null");
        this.delegate = delegate;
    }

    @Override
    /*xxx: 作为一个过滤器 在 容器的 applicationFilterChain 进行过滤*/
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        /*xxx: 懒实例化过滤器代理对象 */
        Filter delegateToUse = this.delegate;

        /*xxx: 执行过滤器代理*/
        invokeDelegate(delegateToUse, request, response, filterChain);
    }

    protected void invokeDelegate(
            Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        /*xxx: 通过过滤器代理进行过滤操作*/
        delegate.doFilter(request, response, filterChain);
    }
}
<filter>
        <!--xxx: 需要注意,这个名字是固定的(在不更改默认源码架构的情况下)-->
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
/*xxx: web上下文初始化器,正常情况下,应该采用这个配置*/
public abstract class AbstractSecurityWebApplicationInitializer
		implements WebApplicationInitializer {
    
    public final void onStartup(ServletContext servletContext) throws ServletException {
        insertSpringSecurityFilterChain(servletContext);
    }

    private void insertSpringSecurityFilterChain(ServletContext servletContext) {
        String filterName = "springSecurityFilterChain";
        DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
                filterName);

        registerFilter(servletContext, true, filterName, springSecurityFilterChain);
    }

    private final void registerFilter(ServletContext servletContext,
                                      boolean insertBeforeOtherFilters, String filterName, Filter filter) {
        Dynamic registration = servletContext.addFilter(filterName, filter);
        EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
        /*xxx: 配置拦截模式*/
        registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters,
                "/*");
    }
}

更多相关知识可参考: springMVC学习笔记-三个初始化器章节中WebApplicationInitializer部分内容

# 与SpringBoot环境的结合方式

@ConditionalOnClass({ 
		AbstractSecurityWebApplicationInitializer.class,
		SessionCreationPolicy.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration {
    @Bean
    /*xxx: 这个名字也至关重要 */
    @ConditionalOnBean("springSecurityFilterChain")
    public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
            SecurityProperties securityProperties) {
        DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
                "springSecurityFilterChain");
        registration.setOrder(securityProperties.getFilter().getOrder());
        registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
        return registration;
    }
}
public class DelegatingFilterProxyRegistrationBean extends AbstractFilterRegistrationBean<DelegatingFilterProxy>
		implements ApplicationContextAware {
    @Override
    public DelegatingFilterProxy getFilter() {
        return new DelegatingFilterProxy(this.targetBeanName, getWebApplicationContext()) {
            @Override
            protected void initFilterBean() throws ServletException {
            }
        };
    }
}

更多相关知识可参考:springMVC学习笔记-三个初始化器章节中ServletContextInitializer部分内容

# 过滤链组装--逻辑结构设计

public interface SecurityBuilder<O> {
    /*xxx: 过滤链构造*/
    O build() throws Exception;
}

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
    private AtomicBoolean building = new AtomicBoolean();

    /*xxx: 过滤链*/
    private O object;

    public final O build() throws Exception {
        if (this.building.compareAndSet(false, true)) {
            this.object = doBuild();
            return this.object;
        }
    }

    /*xxx: 执行构建*/
    protected abstract O doBuild() throws Exception;
}
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
		extends AbstractSecurityBuilder<O> {
    /*xxx: 配置项注册表*/
    private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();

    @Override
    protected final O doBuild() throws Exception {
        synchronized (configurers) {
            init();
            configure();
           return performBuild();
        }
    }

    /*xxx: 初始化*/
    private void init() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
        for (SecurityConfigurer<O, B> configurer : configurers) {
            configurer.init((B) this);
        }
        
    }

    /*xxx: 配置*/
    private void configure() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

        for (SecurityConfigurer<O, B> configurer : configurers) {
            configurer.configure((B) this);
        }
    }
    
    /*xxx: 执行构建*/
    protected abstract O performBuild() throws Exception;

    /*xxx: 收集配置*/
    /*xxx: 注意,这里收集的 SecurityConfigurerAdapter ,可以是针对单个过滤链的配置,也可以增加过滤器链*/
    /*xxx: 配置是添加过滤器链,还是配置过滤器,取决于配置项的 init行为*/
    public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
            throws Exception {
        configurer.setBuilder((B) this);
        add(configurer);
        return configurer;
    }

    private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
        /*xxx: 配置收集*/
        synchronized (configurers) {
            Class clazz = configurer.getClass();
            List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
                    .get(clazz) : null;
            if (configs == null) {
                configs = new ArrayList<SecurityConfigurer<O, B>>(1);
            }
            configs.add(configurer);
            this.configurers.put(clazz, configs);
        }
    }
}
public final class WebSecurity extends
		AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
		SecurityBuilder<Filter>, ApplicationContextAware {
    
    private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>();

    private final List<RequestMatcher> ignoredRequests = new ArrayList<>();
    
    @Override
    protected Filter performBuild() throws Exception {
        int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
        List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
                chainSize);

        /*xxx: 构建过滤链*/
        for (RequestMatcher ignoredRequest : ignoredRequests) {
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
        }
        /*xxx: 构建过滤链*/
        for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
            securityFilterChains.add(securityFilterChainBuilder.build());
        }

        /*xxx: 构建过滤链代理*/
        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

        Filter result = filterChainProxy;
        
        return result;
    }
}

# 过滤配置器新建过滤链的情况

public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {
    public void init(final WebSecurity web) throws Exception {
        final HttpSecurity http = getHttp();
        web.addSecurityFilterChainBuilder(http);
    }
}

# 过滤配置器编辑过滤链的情况

public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
		AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
    @Override
    /*xxx: 注意参数类型的变化*/
    public void init(H http) throws Exception {
        if (authenticationProvider == null) {
            authenticationProvider = new AnonymousAuthenticationProvider(getKey());
        }
        if (authenticationFilter == null) {
            authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal,
                    authorities);
        }
        authenticationProvider = postProcess(authenticationProvider);
        http.authenticationProvider(authenticationProvider);
    }
}

# 过滤链编辑--逻辑结构设计

public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
		SecurityBuilder<DefaultSecurityFilterChain> {
    /*xxx: 在过滤器之后加入过滤器*/
    H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);

    H addFilter(Filter filter);

    /*xxx: 移除过滤器构造器*/
    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(
            Class<C> clazz);

    /*xxx: 添加认证管理器 */
    H authenticationProvider(AuthenticationProvider authenticationProvider);

    /*xxx: 添加用户信息服务*/
    H userDetailsService(UserDetailsService userDetailsService) throws Exception;
}

public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>,
        HttpSecurityBuilder<HttpSecurity> {
    /*xxx: 提供了多个快捷的链式配置项,包括sessionManage,formLogin,rememberMe,cors等等*/

    @Override
    /*xxx: http默认为一条过滤链*/
    protected DefaultSecurityFilterChain performBuild() throws Exception {
        Collections.sort(filters, comparator);
        return new DefaultSecurityFilterChain(requestMatcher, filters);
    }
}

# 过滤链构造器--逻辑结构设计

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
    /*xxx: 各个配置器的初始化方法*/
    void init(B builder) throws Exception;

    /*xxx: 各个配置器统一调用的配置方法*/
    void configure(B builder) throws Exception;
}

public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends
        SecurityConfigurer<Filter, T> {
}

public abstract class WebSecurityConfigurerAdapter implements
        WebSecurityConfigurer<WebSecurity> {
    /*xxx: webSecurity的初始化钩子*/
    public void init(final WebSecurity web) throws Exception {
        final HttpSecurity http = getHttp();
        web.addSecurityFilterChainBuilder(http);
    }

    protected final HttpSecurity getHttp() throws Exception {
        if (http != null) {
            return http;
        }

        http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
                sharedObjects);

        if (!disableDefaults) {
            http.csrf().and()
                    .addFilter(new WebAsyncManagerIntegrationFilter())
                    .exceptionHandling().and()
                    .headers().and()
                    /*xxx: 会话管理*/
                    .sessionManagement().and()
                    .securityContext().and()
                    .requestCache().and()
                    .anonymous().and()
                    .servletApi().and()
                    .apply(new DefaultLoginPageConfigurer<>()).and()
                    .logout();
        }
    }

    /*xxx: 授权配置*/
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().and()
                .httpBasic();
    }

    /*xxx: 注意这个configure 与上面的configure的区别 */
    /*xxx: 该函数是 过滤链构造时的一个钩子函数,详见: AbstractConfiguredSecurityBuilder的configure方法 */
    /*xxx: 可用于添加 过滤器 */
    @Override
    public void configure(WebSecurity web) throws Exception {
    }
}

# 过滤链流程设计

/*xxx: springSecuirty 用来负责 过滤器链的选择 ,springSecurity的实际入口 */
public class FilterChainProxy extends GenericFilterBean {
    private List<SecurityFilterChain> filterChains;

    public FilterChainProxy(List<SecurityFilterChain> filterChains) {
        this.filterChains = filterChains;
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        doFilterInternal(request, response, chain);
    }

    private void doFilterInternal(ServletRequest request, ServletResponse response,
                                  FilterChain chain) throws IOException, ServletException {
        FirewalledRequest fwRequest = firewall
                .getFirewalledRequest((HttpServletRequest) request);

        /*xxx: 从匹配的过滤链条中,获取过滤器列表 */
        List<Filter> filters = getFilters(fwRequest);

        /*xxx: 如果过滤器列表为空,则跳过 */
        if (filters == null || filters.size() == 0) {
            chain.doFilter(fwRequest, fwResponse);
            return;
        }
        /*xxx: 否则,根据过滤器列表,构造虚拟过滤链*/
        /*xxx: 则根据过滤器列表,创建一个虚拟过滤器链,并进行过滤 */
        VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
        vfc.doFilter(fwRequest, fwResponse);
    }

    /*xxx: springSecurity中,最重要的方法,获取过滤链中的过滤器列表 */
    private List<Filter> getFilters(HttpServletRequest request) {
        /*xxx: 从所有的过滤链中,进行筛选,采用首次匹配原则*/
        for (SecurityFilterChain chain : filterChains) {
            if (chain.matches(request)) {
                return chain.getFilters();
            }
        }

        return null;
    }
}
/*xxx: springSecuirty 用来负责 过滤器链的选择 ,springSecurity的实际入口 */
public class FilterChainProxy extends GenericFilterBean {
    private static class VirtualFilterChain implements FilterChain {
        private int currentPosition = 0;

        /*xxx: 原生过滤链*/
        private final FilterChain originalChain;
        
        @Override
        public void doFilter(ServletRequest request, ServletResponse response)
                throws IOException, ServletException {
            if (currentPosition == size) {
                /*xxx: 当springSecurity的虚拟过滤链执行完毕后,需要再次执行 应用层面的过滤链*/
                originalChain.doFilter(request, response);
            }
            else {
                currentPosition++;
                Filter nextFilter = additionalFilters.get(currentPosition - 1);
                nextFilter.doFilter(request, response, this);
            }
        }
    }
}

# 默认过滤链

@Configuration
/*xxx: spring-security的默认配置项,可以自动配置*/
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    @Bean(name = "springSecurityFilterChain")
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();

        /*xxx: 在没有配置的情况下,采用默认配置*/
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();
    }
}
public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {
    protected final HttpSecurity getHttp() throws Exception {
        http
                .csrf().and()
                .addFilter(new WebAsyncManagerIntegrationFilter())
                .exceptionHandling().and()
                .headers().and()
                /*xxx: 会话管理*/
                .sessionManagement().and()
                .securityContext().and()
                .requestCache().and()
                .anonymous().and()
                .servletApi().and()
                .apply(new DefaultLoginPageConfigurer<>()).and()
                .logout();

        configure(http);
        return http;
    }

    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().and()
                .httpBasic();
    }
}

public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>,
        HttpSecurityBuilder<HttpSecurity> {
    @Override
    protected DefaultSecurityFilterChain performBuild() throws Exception {
        Collections.sort(filters, comparator);
        return new DefaultSecurityFilterChain(requestMatcher, filters);
    }
}
/*xxx: 过滤链*/
public interface SecurityFilterChain {

	boolean matches(HttpServletRequest request);

	List<Filter> getFilters();
}

public final class DefaultSecurityFilterChain implements SecurityFilterChain {
    /*xxx: 匹配器*/
    private final RequestMatcher requestMatcher;
    /*xxx: 过滤链中的过滤器集合*/
    private final List<Filter> filters;

    public List<Filter> getFilters() {
        return filters;
    }

    public boolean matches(HttpServletRequest request) {
        return requestMatcher.matches(request);
    }
}

# 认证--应用设计

public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
		extends AbstractHttpConfigurer<T, B> {
    private F authFilter;

    protected AbstractAuthenticationFilterConfigurer(F authenticationFilter,
                                                     String defaultLoginProcessingUrl) {
        this.authFilter = authenticationFilter;

        if (defaultLoginProcessingUrl != null) {
            loginProcessingUrl(defaultLoginProcessingUrl);
        }
    }

    public T loginProcessingUrl(String loginProcessingUrl) {
        this.loginProcessingUrl = loginProcessingUrl;
        authFilter
                .setRequiresAuthenticationRequestMatcher(createLoginProcessingUrlMatcher(loginProcessingUrl));
        return getSelf();
    }

    protected abstract RequestMatcher createLoginProcessingUrlMatcher(
            String loginProcessingUrl);

    @Override
    public void configure(B http) throws Exception {
        authFilter.setAuthenticationManager(http
                .getSharedObject(AuthenticationManager.class));
        authFilter.setAuthenticationSuccessHandler(successHandler);
        authFilter.setAuthenticationFailureHandler(failureHandler);

        if (authenticationDetailsSource != null) {
            authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
        }

        SessionAuthenticationStrategy sessionAuthenticationStrategy = http
                .getSharedObject(SessionAuthenticationStrategy.class);
        if (sessionAuthenticationStrategy != null) {
            authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
        }

        RememberMeServices rememberMeServices = http
                .getSharedObject(RememberMeServices.class);
        if (rememberMeServices != null) {
            authFilter.setRememberMeServices(rememberMeServices);
        }

        F filter = postProcess(authFilter);
        http.addFilter(filter);
    }
}
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
		AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
    @Override
    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }

    @Override
    public void init(H http) throws Exception {
        super.init(http);
        initDefaultLoginFilter(http);
    }

    private void initDefaultLoginFilter(H http) {
        DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
                .getSharedObject(DefaultLoginPageGeneratingFilter.class);
        if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
            /*xxx: 登录页地址*/
            loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
            /*xxx: 认证地址*/
            loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
        }
    }
}

# 认证过滤器--逻辑设计

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
    /*xxx: 认证管理器*/
    private AuthenticationManager authenticationManager;

    /*xxx:记住我的服务*/
    private RememberMeServices rememberMeServices = new NullRememberMeServices();

    /*xxx: session认证策略*/
    private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

    /*xxx: 结果处理器*/
    private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

    /*xxx: 进行过滤的方法 */
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        /*xxx: 首先判断,是否符合当前的认证规则,不符合则放行*/
        if (!requiresAuthentication(request, response)) {
            chain.doFilter(request, response);

            return;
        }

        /*xxx: 获取认证信息 */
        Authentication  authResult = attemptAuthentication(request, response);

        /*xxx: 进行session策略的认证 */
        sessionStrategy.onAuthentication(authResult, request, response);

        /*xxx: 调用认证成功处理器对结果进行处理*/
        successfulAuthentication(request, response, chain, authResult);
    }

    /*xxx: 尝试进行认证*/
    public abstract Authentication attemptAuthentication(HttpServletRequest request,
                                                         HttpServletResponse response) throws AuthenticationException, IOException,
            ServletException;
}
/*xxx: 用户名密码过滤器,spring3.0开始设计*/
public class UsernamePasswordAuthenticationFilter extends
		AbstractAuthenticationProcessingFilter {
    /*xxx: 尝试进行认证*/
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        /*xxx: 生成一个基本的 authentication 令牌*/
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                username, password);

        /*xxx: 为该 authentication 设置附加信息*/
        setDetails(request, authRequest);

        /*xxx: 调用 认证管理器,对令牌进行 认证*/
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

# 认证架构--逻辑设计

/*xxx: 一次完整的认证 可以包含多个 provider,由  providerManager进行管理*/
	/*xxx: 认证管理器 */
public interface AuthenticationManager {
    /*xxx: 迭代验证,直到有一个验证通过,则跳出*/
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
}

/*xxx: springSecurity 默认使用它来完成 迭代认证流程*/
public class ProviderManager implements AuthenticationManager, MessageSourceAware,
        InitializingBean {
    /*xxx: 认证提供器集合*/
    private List<AuthenticationProvider> providers = Collections.emptyList();

    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        Authentication result;
        /*xxx: 获取所有的认证提供器,迭代对其进行认证 */
        for (AuthenticationProvider provider : getProviders()) {
            if (!provider.supports(toTest)) {
                continue;
            }

            /*xxx: 如果当前的 认证提供器,支持该令牌的认证,则对其进行认证*/
             result = provider.authenticate(authentication);

            /*xxx: 认证成功后,需要将源Token 的详细信息 拷贝到 目标Token 中 */
            /*xxx: 拷贝成功后,不再尝试后续的认证*/
            if (result != null) {
                copyDetails(authentication, result);
                break;
            }
        }

        return result;
    }
}
public interface AuthenticationProvider {
    /*xxx: 验证过程,成功则返回一个验证完成的 Authentication*/
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;

    /*xxx: 是否支持当前的Authentication类型*/
    boolean supports(Class<?> authentication);
}

由此可以知道,在典型的http认证场景中,真正提供认证的不是AuthenticationManager,而是:AuthenticationProvider,它们是没有关系的两个类
与http认证不同的是,oauth2协议的资源服务器访问过程,则没有采用这一套体系,而是使用的原生OAuth2AuthenticationManager,继承自AuthenticationManager

# 认证主体流程--流程设计

public abstract class AbstractUserDetailsAuthenticationProvider implements
        AuthenticationProvider, InitializingBean, MessageSourceAware {
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        /*xxx: 从令牌中,获取用户名*/
        String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
                : authentication.getName();

        /*xxx: 从缓存中,获取用户信息*/
        UserDetails user = this.userCache.getUserFromCache(username);

        if (user == null) {
            /*xxx: 首先先检索用户 */
            user = retrieveUser(username,
                    (UsernamePasswordAuthenticationToken) authentication);
        }
        /*xxx: 检测用户账号是否可用: 包括是否锁定,是否冻结,是否过期*/
        preAuthenticationChecks.check(user);
        /*xxx: 附加认证检查,默认情况下,该方法就是检查 是否与给定的密码匹配*/
        additionalAuthenticationChecks(user,
                (UsernamePasswordAuthenticationToken) authentication);

        /*xxx: 检查用户密码是否过期 */
        postAuthenticationChecks.check(user);

        /*xxx: 返回认证通过的 Authentication */
        return createSuccessAuthentication(principalToReturn, authentication, user);
    }

    /*xxx: 检索用户 */
    protected abstract UserDetails retrieveUser(String username,
                                                UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException;
}
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    /*xxx: 为认证提供数据来源*/
    private UserDetailsService userDetailsService;

    private UserDetailsPasswordService userDetailsPasswordService;
    
    /*xxx: 检索用户*/
    protected final UserDetails retrieveUser(String username,
                                             UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {

        /*xxx: 根据用户名,获取用户信息,需要遵循 springSecurity的模型规则。 通过 UserService*/
        UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
        return loadedUser;
    }
}
public interface UserDetailsService {
    /*xxx: 根据用户名查询用户*/
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

public class JdbcDaoImpl extends JdbcDaoSupport
        implements UserDetailsService, MessageSourceAware {
    /*xxx: 通过jdbc实现的数据源服务,实现略*/    
}

# 认证令牌--逻辑设计

public abstract class AbstractAuthenticationToken implements Authentication,
        CredentialsContainer {
    private final Collection<GrantedAuthority> authorities;
    private Object details;
    private boolean authenticated = false;

    public boolean isAuthenticated() {
        return authenticated;
    }
}

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    private final Object principal;
    private Object credentials;
}

# 认证前置流程--从session中提取认证信息

public class SecurityContextPersistenceFilter extends GenericFilterBean {
    static final String FILTER_APPLIED = "__spring_security_scpf_applied";
    
    private SecurityContextRepository repo;

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        if (request.getAttribute(FILTER_APPLIED) != null) {
            chain.doFilter(request, response);
            return;
        }

        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

        HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
                response);
        SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

        /*xxx: 将恢复的认证信息,保存至当前线程上下文中 */
        SecurityContextHolder.setContext(contextBeforeChainExecution);

        chain.doFilter(holder.getRequest(), holder.getResponse());
        
        
    }
}
public interface SecurityContextRepository {
    SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
}

public class HttpSessionSecurityContextRepository implements SecurityContextRepository {
    public static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
    
    private String springSecurityContextKey = SPRING_SECURITY_CONTEXT_KEY;

    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        HttpServletRequest request = requestResponseHolder.getRequest();
        HttpServletResponse response = requestResponseHolder.getResponse();
        HttpSession httpSession = request.getSession(false);

        SecurityContext context = readSecurityContextFromSession(httpSession);
        
        return contex;
    }

    private SecurityContext readSecurityContextFromSession(HttpSession httpSession) {
        Object contextFromSession = httpSession.getAttribute(springSecurityContextKey);
        return (SecurityContext) contextFromSession;
    }
}

# 认证后置流程--认证信息保存至session

public class SecurityContextPersistenceFilter extends GenericFilterBean {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        try {
            /*xxx: 省略其他抽象...*/
            chain.doFilter(holder.getRequest(), holder.getResponse());
        }finally {
            SecurityContext contextAfterChainExecution = SecurityContextHolder
                    .getContext();
            
            SecurityContextHolder.clearContext();

            repo.saveContext(contextAfterChainExecution, holder.getRequest(),
                    holder.getResponse());
            request.removeAttribute("__spring_security_scpf_applied");
        }
    }
}
public interface SecurityContextRepository {
    void saveContext(SecurityContext context, HttpServletRequest request,
                     HttpServletResponse response);
}

public class HttpSessionSecurityContextRepository implements SecurityContextRepository {
    public void saveContext(SecurityContext context, HttpServletRequest request,
                            HttpServletResponse response) {
        SaveContextOnUpdateOrErrorResponseWrapper responseWrapper = WebUtils
                .getNativeResponse(response,
                        SaveContextOnUpdateOrErrorResponseWrapper.class);
        if (!responseWrapper.isContextSaved()) {
            responseWrapper.saveContext(context);
        }
    }
}
public abstract class SaveContextOnUpdateOrErrorResponseWrapper
		extends OnCommittedResponseWrapper {
    protected abstract void saveContext(SecurityContext context);
}

final class SaveToSessionResponseWrapper extends
        SaveContextOnUpdateOrErrorResponseWrapper {
    @Override
    protected void saveContext(SecurityContext context) {
        final Authentication authentication = context.getAuthentication();
        HttpSession httpSession = request.getSession(false);

        /*xxx: 将上下文信息保存至session中*/
        if (httpSession != null) {
            httpSession.setAttribute("SPRING_SECURITY_CONTEXT", context);
        }
    }
}

# 认证后置流程--session控制

session与用户绑定

public interface SessionAuthenticationStrategy {
    void onAuthentication(Authentication authentication, HttpServletRequest request,
                          HttpServletResponse response) throws SessionAuthenticationException;
}

public class RegisterSessionAuthenticationStrategy implements
		SessionAuthenticationStrategy {
    private final SessionRegistry sessionRegistry;

    public void onAuthentication(Authentication authentication,
                                 HttpServletRequest request, HttpServletResponse response) {
        sessionRegistry.registerNewSession(request.getSession().getId(),
                authentication.getPrincipal());
    }
}

session并发控制

public interface SessionAuthenticationStrategy {
    void onAuthentication(Authentication authentication, HttpServletRequest request,
                          HttpServletResponse response) throws SessionAuthenticationException;
}

/*xxx: 会话并发控制策略  */
public class ConcurrentSessionControlAuthenticationStrategy implements
        MessageSourceAware, SessionAuthenticationStrategy {
    /*xxx: 默认允许的并发数为1, 新的会话会踢掉旧的会话*/
    private int maximumSessions = 1;

    private final SessionRegistry sessionRegistry;

    public ConcurrentSessionControlAuthenticationStrategy(SessionRegistry sessionRegistry) {
        this.sessionRegistry = sessionRegistry;
    }

    public void onAuthentication(Authentication authentication,
                                 HttpServletRequest request, HttpServletResponse response) {
        final List<SessionInformation> sessions = sessionRegistry.getAllSessions(
                authentication.getPrincipal(), false);

        int sessionCount = sessions.size();
        int allowedSessions = getMaximumSessionsForThisUser(authentication);
        /*xxx: 允许的并发数大于当前并发数时,不做处理*/
        if (sessionCount < allowedSessions) {
            return;
        }

        /*xxx: -1表示不做限制*/
        if (allowedSessions == -1) {
            return;
        }

        /*xxx: 进行策略判断 */
        allowableSessionsExceeded(sessions, allowedSessions, sessionRegistry);
    }

    protected void allowableSessionsExceeded(List<SessionInformation> sessions,
                                             int allowableSessions, SessionRegistry registry)
            throws SessionAuthenticationException {
        sessions.sort(Comparator.comparing(SessionInformation::getLastRequest));
        int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
        List<SessionInformation> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);
        /*xxx: 当新会话建立时,最早的会话过期*/
        /*xxx: 注意,这一步只是标志session过期,但是需要该标志被检测的时候,才会进行剔除*/
        for (SessionInformation session: sessionsToBeExpired) {
            session.expireNow();
        }
    }
}

session并发管理的逻辑为:

  • 用户的principal对应了多个 ids;
  • 每个ids保存了session的信息;
  • 以 UserDetails 为键,因此在覆写自定义的userDetails时,必须覆写 hashCode 和 equals方法

# session管理

# 授权--逻辑结构设计

# 投票管理器

/*xxx: 访问决策管理器 */
public interface AccessDecisionManager {
    /*xxx: 资源通行投票*/
    void decide(Authentication authentication, Object object,
                Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
            InsufficientAuthenticationException;

    /*xxx: 是否能够参与投票*/
    boolean supports(Class<?> clazz);
}

/*xxx: 抽象访问决策器*/
public abstract class AbstractAccessDecisionManager implements AccessDecisionManager,
        InitializingBean, MessageSourceAware {
    /*xxx: 投票器池*/
    private List<AccessDecisionVoter<? extends Object>> decisionVoters;

    public boolean supports(Class<?> clazz) {
        for (AccessDecisionVoter voter : this.decisionVoters) {
            if (!voter.supports(clazz)) {
                return false;
            }
        }

        return true;
    }
}
/*xxx: 乐观投票器,只要有一个通过就算通过*/
public class AffirmativeBased extends AbstractAccessDecisionManager {
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
        int deny = 0;

        for (AccessDecisionVoter voter : getDecisionVoters()) {
            int result = voter.vote(authentication, object, configAttributes);

            switch (result) {
                /*xxx: 有一个通过,就算通过*/
                case AccessDecisionVoter.ACCESS_GRANTED:
                    return;

                case AccessDecisionVoter.ACCESS_DENIED:
                    deny++;
                    break;

                default:
                    break;
            }
        }
    }
}
/*xxx: 少数服从多数的投票器,如果通过的票数,多于反对的票数,则整体通过,反之同理*/
public class ConsensusBased extends AbstractAccessDecisionManager {
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
        int grant = 0;
        int deny = 0;

        for (AccessDecisionVoter voter : getDecisionVoters()) {
            int result = voter.vote(authentication, object, configAttributes);
            /*xxx: 记录通过的票数,以及不通过的票数*/
            switch (result) {
                case AccessDecisionVoter.ACCESS_GRANTED:
                    grant++;
                    break;

                case AccessDecisionVoter.ACCESS_DENIED:
                    deny++;
                    break;

                default:
                    break;
            }
        }

        if (grant > deny) {
            return;
        }

        if (deny > grant) {
            /*xxx: 抛授权异常...*/
        }
    }
}
/*xxx: 悲观投票器,所有的投票器赞成,才算通过。有一个反对,则不通过*/
public class UnanimousBased extends AbstractAccessDecisionManager {
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> attributes) throws AccessDeniedException {
        int grant = 0;
        for (AccessDecisionVoter voter : getDecisionVoters()) {
            int result = voter.vote(authentication, object, singleAttributeList);
            
            switch (result) {
                case AccessDecisionVoter.ACCESS_GRANTED:
                    grant++;
                    break;

                case AccessDecisionVoter.ACCESS_DENIED:
                    /*xxx: 投反对票,直接抛出资源访问异常*/
                    throw new AccessDeniedException(messages.getMessage(
                            "AbstractAccessDecisionManager.accessDenied",
                            "Access is denied"));
                default:
                    break;
            }
        }
    }
}

# 投票器

/*xxx: 访问策略投票器*/
public interface AccessDecisionVoter<S> {
    int ACCESS_GRANTED = 1;
    int ACCESS_ABSTAIN = 0;
    int ACCESS_DENIED = -1;

    boolean supports(Class<?> clazz);

    int vote(Authentication authentication, S object,
             Collection<ConfigAttribute> attributes);
}
public class RoleVoter implements AccessDecisionVoter<Object> {
    private String rolePrefix = "ROLE_";

    public boolean supports(Class<?> clazz) {
        return true;
    }

    public boolean supports(ConfigAttribute attribute) {
        if ((attribute.getAttribute() != null)
                && attribute.getAttribute().startsWith(getRolePrefix())) {
            return true;
        }
        else {
            return false;
        }
    }

    public int vote(Authentication authentication, Object object,
                    Collection<ConfigAttribute> attributes) {
        int result = ACCESS_ABSTAIN;
        Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);

        for (ConfigAttribute attribute : attributes) {
            if (this.supports(attribute)) {
                result = ACCESS_DENIED;
                for (GrantedAuthority authority : authorities) {
                    /*xxx: 判断是否有对应的角色信息*/
                    if (attribute.getAttribute().equals(authority.getAuthority())) {
                        return ACCESS_GRANTED;
                    }
                }
            }
        }

        return result;
    }
}

# 授权--过程设计

public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements
		Filter {
    private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";

    /*xxx: 默认过滤链的最后一个过滤器*/
    /*xxx: 抛出的异常,会被倒数第二个过滤器ExceptionTranslationFilter,进行处理*/
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        /*xxx: 将请求封装为 过滤器执行器*/
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        /*xxx: 调用执行器*/
        invoke(fi);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        /*xxx: 进行资源投票,如果授权未通过,则会抛错 */
        /*xxx: 在这个阶段,也可能抛 认证异常,如果之前未进行认证*/
        InterceptorStatusToken token = super.beforeInvocation(fi);

        /*xxx: 对拦截器状态令牌,进行后置处理*/
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        }
        finally {
            super.finallyInvocation(token);
        }
    }
}

public class FilterInvocation {
    private FilterChain chain;
    private HttpServletRequest request;
    private HttpServletResponse response;
}
public abstract class AbstractSecurityInterceptor implements InitializingBean,
		ApplicationEventPublisherAware, MessageSourceAware {
    /*xxx: 返回 拦截器状态令牌 */
    protected InterceptorStatusToken beforeInvocation(Object object) {
        /*xxx: 获取SecurityMedataSource元数据*/
        Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
                .getAttributes(object);

        /*xxx: 通过授权管理器,进行授权 */
        try {
            this.accessDecisionManager.decide(authenticated, object, attributes);
        }catch (AccessDeniedException accessDeniedException) {
            throw accessDeniedException;
        }
    }
}
public interface SecurityMetadataSource extends AopInfrastructureBean {
    Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException;
}

public class DefaultFilterInvocationSecurityMetadataSource implements
        FilterInvocationSecurityMetadataSource {
    
    private final Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;

    public DefaultFilterInvocationSecurityMetadataSource(
            LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap) {

        this.requestMap = requestMap;
    }
    
    public Collection<ConfigAttribute> getAttributes(Object object) {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
                .entrySet()) {
            if (entry.getKey().matches(request)) {
                return entry.getValue();
            }
        }
        return null;
    }
}

# 授权--元数据准备流程

public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {
    protected void configure(HttpSecurity http) throws Exception {
        http
                /*xxx: 链式配置,根据配置拦截器的先后顺序,依次生效*/
                .authorizeRequests().antMatchers("/test/**").hasAuthority("ROLE_TEST")
                .anyRequest().authenticated()
                .and()
                /*xxx: 这个匹配拦截器,是针对过滤链的*/
                /*xxx: 上方的匹配拦截器,是针对授权过程的*/
                .antMatcher("/mySecurity/**");
    }
}
public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>,
        HttpSecurityBuilder<HttpSecurity> {
    /*xxx: 通过调用其 anyRequest(),antMatchers(),regexMatchers(),等方法来匹配系统的URL*/
    public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
            throws Exception {
        ApplicationContext context = getContext();
        return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context))
                .getRegistry();
    }

    private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
            C configurer) throws Exception {
        C existingConfig = (C) getConfigurer(configurer.getClass());
        if (existingConfig != null) {
            return existingConfig;
        }
        /*xxx: 收集配置,略*/
        return apply(configurer);
    }
}
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
		extends
		AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
    private final ExpressionInterceptUrlRegistry REGISTRY;

    public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
        this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
    }
}

public class ExpressionInterceptUrlRegistry
        extends
        AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
}

abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
        extends AbstractConfigAttributeRequestMatcherRegistry<T> {
    
}

public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
        AbstractRequestMatcherRegistry<C> {
    /*xxx: 通过url描述信息进行拦截*/
    private List<UrlMapping> urlMappings = new ArrayList<>();

    /*xxx: 未配置完成的映射匹配 */
    private List<RequestMatcher> unmappedMatchers;
    
    final void addMapping(UrlMapping urlMapping) {
        /*xxx: 每次添加映射的时候,都会将未完成的映射匹配器置空,这非常重要*/
        this.unmappedMatchers = null;
        this.urlMappings.add(urlMapping);
    }

    /*xxx: 可以指定优先级的方式指定拦截器*/
    /*xxx: PermitAllSupport.permitAll()方法有调用*/
    final void addMapping(int index, UrlMapping urlMapping) {
        this.urlMappings.add(index, urlMapping);
    }

    final LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> createRequestMap() {
        if (unmappedMatchers != null) {
            /*xxx: 抛错...*/
        }
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
        for (UrlMapping mapping : getUrlMappings()) {
            RequestMatcher matcher = mapping.getRequestMatcher();
            Collection<ConfigAttribute> configAttrs = mapping.getConfigAttrs();
            requestMap.put(matcher, configAttrs);
        }
        return requestMap;
    }
}

static final class UrlMapping {
    private RequestMatcher requestMatcher;
    private Collection<ConfigAttribute> configAttrs;
}

public abstract class AbstractRequestMatcherRegistry<C> {
    private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
    
    public C anyRequest() {
        return requestMatchers(ANY_REQUEST);
    }

    public C requestMatchers(RequestMatcher... requestMatchers) {
        return chainRequestMatchers(Arrays.asList(requestMatchers));
    }

    public C antMatchers(String... antPatterns) {
        return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
    }

    protected abstract C chainRequestMatchers(List<RequestMatcher> requestMatchers);
}

# 授权元数据-逻辑设计

public interface ConfigAttribute extends Serializable {
    String getAttribute();
}

public class SecurityConfig implements ConfigAttribute {
    private final String attrib;

    @Override
    public String getAttribute() {
        return this.attrib;
    }
}

class WebExpressionConfigAttribute implements ConfigAttribute,
        EvaluationContextPostProcessor<FilterInvocation> {
    private final Expression authorizeExpression;

    @Override
    public String getAttribute() {
        return null;
    }

    @Override
    /*xxx: 通过这个方法进行辅助投票的*/
    public EvaluationContext postProcess(EvaluationContext context, FilterInvocation fi) {
        return this.postProcessor == null ? context
                : this.postProcessor.postProcess(context, fi);
    }
}

# 关键过滤器流程设计

# 异常转换器流程设计

public class ExceptionTranslationFilter extends GenericFilterBean {
    /*xxx: 默认情况下,这个异常转换的过滤器,位于默认过滤器链的倒数第二个位置,用于处理 授权失败的情况*/
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            chain.doFilter(request, response);
        }catch (Exception ex) {
            /*xxx: 提取异常类型*/
            Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
            RuntimeException ase = (AuthenticationException) throwableAnalyzer
                    .getFirstThrowableOfType(AuthenticationException.class, causeChain);

            if (ase == null) {
                ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(
                        AccessDeniedException.class, causeChain);
            }

            if (ase != null) {
                /*xxx: 对springSecurity的异常进行处理 */
                handleSpringSecurityException(request, response, chain, ase);
            }else{
                /*xxx: 抛出其它原生错误... 略*/
            }
        }
    }

    /*xxx: 对于出现的错误,有两种处理方式,分别对应了 认证错误(认证错误包含了 匿名认证 的情况),以及 授权错误*/
    private void handleSpringSecurityException(HttpServletRequest request,
                                               HttpServletResponse response, FilterChain chain, RuntimeException exception)
            throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            /*xxx: 第一种,通过认证端口,处理异常 */
            sendStartAuthentication(request, response, chain,
                    (AuthenticationException) exception);
        }else if (exception instanceof AccessDeniedException) {
            if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
                /*xxx: 第一种,通过认证端口,处理异常(当前未匿名认证时,采用该方式) */
                sendStartAuthentication(request, response, chain,
                        new InsufficientAuthenticationException("..."));
            }else{
                /*xxx: 第二种,通过 AccessDeniedHandler进行处理(内部)*/
                accessDeniedHandler.handle(request, response,
                        (AccessDeniedException) exception);
            }
        }
    }

    protected void sendStartAuthentication(HttpServletRequest request,
                                           HttpServletResponse response, FilterChain chain,
                                           AuthenticationException reason) throws ServletException, IOException {
        /*xxx: 该方法,如果之前没有会话信息(即之前的会话请求中,没有sessionId),则会维持会话信息 */
        /*xxx: 通俗说,就是会创建session*/
        requestCache.saveRequest(request, response);

        /*xxx: cas客户端登录,貌似就是用的这种方式*/
        authenticationEntryPoint.commence(request, response, reason);
    }
}
/*xxx: ExceptionTranslationFilter 用于启动身份验证方案*/
	/*xxx: 认证入口点 */
public interface AuthenticationEntryPoint {
    /*xxx: 开始认证*/
    void commence(HttpServletRequest request, HttpServletResponse response,
                  AuthenticationException authException) throws IOException, ServletException;
}
/*xxx: 进行登录,支持两种策略: forward与redirect*/
public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoint,
        InitializingBean {
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {
        String redirectUrl = null;
        if (useForward) {
            redirectUrl = buildHttpsRedirectUrlForRequest(request);
            RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);
            dispatcher.forward(request, response);
            return;
        }else {
            redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
            redirectStrategy.sendRedirect(request, response, redirectUrl);
        }
    }
}
/*xxx: 内部处理 accessDenied的策略*/
public interface AccessDeniedHandler {
    void handle(HttpServletRequest request, HttpServletResponse response,
                AccessDeniedException accessDeniedException) throws IOException,
            ServletException;
}

public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    public void handle(HttpServletRequest request, HttpServletResponse response,
                       AccessDeniedException accessDeniedException) throws IOException,
            ServletException {
        if (!response.isCommitted()) {
            /*xxx: 有错误页的情况下,转发到错误页面*/
            if (errorPage != null) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
                dispatcher.forward(request, response);
            }else {
                response.sendError(HttpStatus.FORBIDDEN.value(),
                        HttpStatus.FORBIDDEN.getReasonPhrase());
            }
        }
    }
}

# session控制过滤器

public final class HttpSecurity extends
		AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
		implements SecurityBuilder<DefaultSecurityFilterChain>,
		HttpSecurityBuilder<HttpSecurity> {
    public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
        return getOrApply(new SessionManagementConfigurer<>());
    }
}

public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
        extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
    @Override
    public void configure(H http) throws Exception {
        SecurityContextRepository securityContextRepository = http
                .getSharedObject(SecurityContextRepository.class);
        
        SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(
                securityContextRepository, getSessionAuthenticationStrategy(http));

        http.addFilter(sessionManagementFilter);

        if (isConcurrentSessionControlEnabled()) {
            ConcurrentSessionFilter concurrentSessionFilter = createConccurencyFilter(http);

            concurrentSessionFilter = postProcess(concurrentSessionFilter);
            http.addFilter(concurrentSessionFilter);
        }
    }

    private boolean isConcurrentSessionControlEnabled() {
        return this.maximumSessions != null;
    }
}
public class SessionManagementFilter extends GenericFilterBean {
    private final SecurityContextRepository securityContextRepository;
    private SessionAuthenticationStrategy sessionAuthenticationStrategy;
    
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        /*xxx: 认证上下文没有当前请求信息,才会进行处理*/
        if (!securityContextRepository.containsContext(request)) {
            Authentication authentication = SecurityContextHolder.getContext()
                    .getAuthentication();
            if (authentication != null && !trustResolver.isAnonymous(authentication)) {
                sessionAuthenticationStrategy.onAuthentication(authentication,
                        request, response);
                
                securityContextRepository.saveContext(SecurityContextHolder.getContext(),
                        request, response);
            }else{
                if (request.getRequestedSessionId() != null
                        && !request.isRequestedSessionIdValid()) {
                    invalidSessionStrategy
                            .onInvalidSessionDetected(request, response);
                }
            }
        }
        chain.doFilter(request, response);
    }
}
public class ConcurrentSessionFilter extends GenericFilterBean {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        HttpSession session = request.getSession(false);

        /*xxx: 剔除本身session*/
        if (session != null) {
            SessionInformation info = sessionRegistry.getSessionInformation(session
                    .getId());

            if (info != null) {
                if (info.isExpired()) {
                    doLogout(request, response);
                }else{
                    sessionRegistry.refreshLastRequest(info.getSessionId());
                }
            }
        }
        chain.doFilter(request, response);
    }
}

# 过滤器对流程控制的影响

  • 过滤器可以在内部终止流程;
  • 过滤器可以编排成链,从而完成指定的功能;
  • 过滤链的执行逻辑结构为树结构的层级遍历,流程既可以在叶子节点终结,也可以在根节点终结;

# 项目关键要素

# 默认情况下,登录密码的校验

  • 校验过程
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    private PasswordEncoder passwordEncoder;
    
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        } else {
            String presentedPassword = authentication.getCredentials().toString();
            if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
                throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
            }
        }
    }
}
  • 密码校验器的设置过程
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {

    @Autowired
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;
        ObjectPostProcessor<Object> objectPostProcessor = (ObjectPostProcessor)context.getBean(ObjectPostProcessor.class);
        WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(context);
        //xxx:从上下文中注入passwordEncoder,并以该encoder作为后续组件的组成部分,构建执行逻辑
        this.authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, passwordEncoder);
    }
    
}