Spring Security 的工作原理/总体架构

目录

1、过滤器的视角

2、DelegatingFilterProxy 委派过滤器代理(类)

2、FilterChainProxy 过滤器链代理(类)

4、SecurityFilterChain 安全过滤器链(接口)

5、Security Filters 安全过滤器实例

6、Spring Security 如何处理安全异常?

7、在认证的时候保存用户请求


        // 释义、解读和思考

1、过滤器的视角

        Spring Security 对 Servlet 支持基于 Servlet 过滤器。下图显示了单个HTTP请求的处理程序的典型分层。

        客户端向应用程序发送请求,容器根据请求 URI 的路径创建一个 FilterChain,其中包含过滤器实例和处理 HttpServletRequest 的 Servlet。// 过滤器链式顺序执行的,具有有序性

        因为 Filter 会影响下游的 Filter 实例和 Servlet,所以调用每个 Filter 的顺序非常重要

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // 省略...
    chain.doFilter(request, response); 
    // 省略...
}

        // doFilter 方法中有一个 FilterChain 入参,FilterChain 也是一个接口,既然 FilterChain 是一个过滤器链,那么它的实现类中肯定包含有一个 Filter 列表(持有一个或多个Filter 对象)。看源码

        // Spring Security 利用过滤器链来实现身份验证和授权

2、DelegatingFilterProxy 委派过滤器代理(类)

        Spring 提供了一个名为 DelegatingFilterProxy 的过滤器代理类,它是 Servlet 容器的生命周期和 Spring 的 ApplicationContext 之间架桥。//这个类是一个通用的过滤器实例

        // 在Spring 中,Spring 管理过滤器的生命周期,所以 Filter 实例也是 Spring 中的一个Bean

        DelegatingFilterProxy 从 ApplicationContext 中查找 Bean Filter-0,然后调用 Bean Filter-0,下面的代码展示了这一过程:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    //获取Bean
	Filter delegate = getFilterBean(someBeanName);
	delegate.doFilter(request, response);
}

        // 总结:DelegatingFilterProxy 这个类就是一个过滤器实例,Spring 通过这个过滤器,去实现一系列的认证和授权操作。

        // 深刻认识下,想想这种做法。

2、FilterChainProxy 过滤器链代理(类)

        Spring Security 的 Servlet 支持包含在 FilterChainProxy 中。

        FilterChainProxy 是 Spring Security 提供的一个特殊过滤器,它允许通过 SecurityFilterChain 向多个过滤器实例委托。FilterChainProxy 是一个Bean,它通常被封装在 DelegatingFilterProxy中。

        //见名知意,过滤器链的代理 FilterChainProxy 中会持有过滤器链的对象

public class FilterChainProxy extends GenericFilterBean {

	private static final Log logger = LogFactory.getLog(FilterChainProxy.class);

	private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(
			".APPLIED");

    // SecurityFilterChain 对象列表
	private List<SecurityFilterChain> filterChains;

    //省略...
}

        // FilterChainProxy -> DelegatingFilterProxy,可以猜想 DelegatingFilterProxy 中的这个 delegate 是不是就是 FilterChainProxy 的实例?源码见分晓

​
public class DelegatingFilterProxy extends GenericFilterBean {
    @Nullable
    private String contextAttribute;
    @Nullable
    private WebApplicationContext webApplicationContext;
    @Nullable
    private String targetBeanName;
    private boolean targetFilterLifecycle;
    @Nullable
    private volatile Filter delegate;  //这里有一个过滤器委托,proxy
    private final Object delegateMonitor;
    //省略...
}

4、SecurityFilterChain 安全过滤器链(接口)

        FilterChainProxy 使用 SecurityFilterChain 来确定应该为当前请求调用哪一个 Spring SecurityFilter 实例

        //选择过滤器链,在FilterChainProxy 中是这样做的

// 返回与提供的URL匹配的第一个过滤器链    
private List<Filter> getFilters(HttpServletRequest request) {
		for (SecurityFilterChain chain : filterChains) {
			if (chain.matches(request)) {
				return chain.getFilters();
			}
		}
		return null;
	}

//一些源码:
//SecurityFilterChain(接口) -> DefaultSecurityFilterChain(实现类) -> 持有RequestMatcher对象 -> matches方法
//RequestMatcher接口用来支持匹配HttpServletRequest的简单策略。匹配策略有很多,此处不多介绍
//RequestMatcher -> AntPathRequestMatcher(实现),servlet通过url路径进行匹配 

        下图显示了 SecurityFilterChain 的角色。

        SecurityFilterChain 中的 Filter 实例是在 FilterChainProxy 中进行注册的(而不是 DelegatingFilterProxy)。

    public FilterChainProxy(SecurityFilterChain chain) {
		this(Arrays.asList(chain));
	}

	public FilterChainProxy(List<SecurityFilterChain> filterChains) {
		this.filterChains = filterChains;
	}

        使用 FilterChainProxy 作为起点的优势://这些特点很重要,仔细看

  1. 这样做为 Spring Security 的所有 Servlet 支持提供了一个起点,如果试图对 Spring Security 的 Servlet 支持进行故障排除,那么在 FilterChainProxy 中添加一个调试点是一个很好的开始。//所有的过滤器都在这里进行注册,然后开始调用,过滤器的调用从FilterChainProxy选择一个过滤器链开始
  2. FilterChainProxy 是 Spring Security 使用的核心,它可以执行一些不可选的任务。例如,清除 SecurityContext 以避免内存泄漏,应用 Spring Security 的HttpFirewall 来保护应用程序免受某些类型的攻击。//不可选的任务,就是必须做的一些事情或者一些通用的功能
  3. 在确定何时调用 SecurityFilterChain 方面提供了更大的灵活性。在 Servlet 容器中,仅根据 URL 调用 Filter 实例。然而,FilterChainProxy 可以通过使用 RequestMatcher 接口,基于 HttpServletRequest 中的任何内容来确定调用。//方便做选择,RequestMatcher -> 匹配策略接口

        下图显示了多个 SecurityFilterChain 实例:

        在 Multiple SecurityFilterChain 图中,FilterChainProxy 决定应该使用哪个 SecurityFilterChain。

        这里有一些匹配规则: 

        FilterChainProxy 只会调用匹配到的第一个 SecurityFilterChain。如请求 URL 为: /api/messages/,它首先匹配的是 SecurityFilterChain-0(匹配规则:/api/**),因此只调用 SecurityFilterChain-0,即使它也匹配 SecurityFilterChain-n(匹配规则:/**)。//执行第一个匹配到的过滤器链

        如果请求 URL/messages/ ,它与SecurityFilterChain-0(匹配规则:/api/**)不匹配,因此 FilterChainProxy 会继续尝试每个 SecurityFilterChain。假设没有其他 SecurityFilterChain 实例匹配,则调用 SecurityFilterChain-n

        需要注意的是,每个 SecurityFilterChain 都是唯一的,并且可以进行单独配置。如果应用程序希望 Spring security 忽略某些请求,那么可以在 SecurityFilterChain 中不设置任何的安全过滤器实例。//SecurityFilterChain 这个里边可以没有任何过滤器,那就是不进行任何拦截

5、Security Filters 安全过滤器实例

        以下是 Spring Security 的过滤器排序的综合列表://按顺序排列的

  1. ForceEagerSessionCreationFilter
  2. ChannelProcessingFilter
  3. WebAsyncManagerIntegrationFilter
  4. SecurityContextPersistenceFilter
  5. HeaderWriterFilter
  6. CorsFilter
  7. CsrfFilter
  8. LogoutFilter
  9. OAuth2AuthorizationRequestRedirectFilter
  10. Saml2WebSsoAuthenticationRequestFilter
  11. X509AuthenticationFilter
  12. AbstractPreAuthenticatedProcessingFilter
  13. CasAuthenticationFilter
  14. OAuth2LoginAuthenticationFilter
  15. Saml2WebSsoAuthenticationFilter
  16. UsernamePasswordAuthenticationFilter
  17. DefaultLoginPageGeneratingFilter
  18. DefaultLogoutPageGeneratingFilter
  19. ConcurrentSessionFilter
  20. DigestAuthenticationFilter
  21. BearerTokenAuthenticationFilter
  22. BasicAuthenticationFilter
  23. RequestCacheAwareFilter
  24. SecurityContextHolderAwareRequestFilter
  25. JaasApiIntegrationFilter
  26. RememberMeAuthenticationFilter
  27. AnonymousAuthenticationFilter
  28. OAuth2AuthorizationCodeGrantFilter
  29. SessionManagementFilter
  30. ExceptionTranslationFilter  //异常处理过滤器
  31. FilterSecurityInterceptor
  32. SwitchUserFilter

        //这些过滤器的排序是Spring官方提供的,后来Spring可能觉得这样展示的意义不大,删去了这部分内容, 补充了一些从日志查看过滤器加载顺序的说明。(过滤器的加载顺序会在Info日志中打印,以实时加载为准)。

6、Spring Security 如何处理安全异常?

        //首先说,这里就是 Spring Security 的工作原理,重中之重,非常重要,虽然讲的是一个异常过滤器,但是实际上是一个执行流程。

        ExceptionTranslationFilter 允许将 AccessDeniedException 和 AuthenticationException 转换为 HTTP 响应。//两个异常,禁止访问 + 认证异常

        ExceptionTranslationFilter 作为安全过滤器之一,自动插入到 FilterChainProxy 中。

        下图显示了 ExceptionTranslationFilter 与其他组件的关系:

        首先,ExceptionTranslationFilter 调用 FilterChain.doFilter(request, response) 来调用应用程序的剩余部分,这里有两种情况,用户未经过认证以及用户被拒绝访问// Continue ProcessingRequest Normally -> 继续正常处理请求

        如果用户未经过身份验证或者抛出了 AuthenticationException,则启动身份验证

  1. 首先清除 SecurityContextHolder,这个是一个 Spring Security 中的一个核心类。
  2. RequestCache:保存 HttpServletRequest 请求,在身份验证成功后可以使用它重复原始请求。//也可以不保存,那么用户就需要重新去请求
  3. AuthenticationEntryPoint 用于从客户端获取请求凭据。例如,它可能重定向到登录页面或发送 WWW-Authenticate 报文头。//AuthenticationEntryPoint(接口) -> 比如重定向到登录页面,要求登录,执行从客户端获取请求凭据的策略

        //以上这三个类都给出了身份验证的大致流程,流程中给出了这些关键类的使用时机,描述了 Spring Security 的大致框架。

        如果是 AccessDeniedException,则拒绝访问。直接调用 AccessDeniedHandler 来处理拒绝访问。// AccessDeniedHandler(接口),也可以自定义处理策略

        如果应用程序没有抛出 AccessDeniedException AuthenticationException,则ExceptionTranslationFilter 不做任何事情。//这个过滤器只处理这两个异常

        ExceptionTranslationFilter 的伪代码逻辑如下:

try {
	filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) { //捕获特定异常
	if (!authenticated || ex instanceof AuthenticationException) {
		startAuthentication(); //启动认证流程
	} else {
		accessDenied(); //决绝策略
	}
}

7、在认证的时候保存用户请求

        当用户请求资源时,如果没有经过身份验证,就需要保存请求信息,当身份验证成功后再重新执行该请求。在 Spring Security 中,通过使用 RequestCache 的实现来保存 HttpServletRequest。//RequestCache是一个接口,请求缓存策略可以有不同的实现

        RequestCacheAwareFilter 和 RequestCache 接口

        HttpServletRequest 保存在 RequestCache 中。当用户成功通过身份验证时,将使用 RequestCache 重新执行原始请求。

        RequestCacheAwareFilter 使用 RequestCache 来保存 HttpServletRequest。默认情况下,使用 HttpSessionRequestCache

        下面的代码演示了如何定制 RequestCache 的实现,该实现用于在参数 continue 存在的情况下检查保存请求的 HttpSession。//这里存储的是一个标记,通过RequestCacheAwareFilter过滤器使用

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
	requestCache.setMatchingRequestParameterName("continue");
	http
		// ...
		.requestCache((cache) -> cache.requestCache(requestCache));
	return http.build();
}

        如果不希望在会话中存储用户未经身份验证的请求,可以使用 NullRequestCache 实现。//不保存会话信息,直接重定向到登录页

@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
    RequestCache nullRequestCache = new NullRequestCache();
    http
        // ...
        .requestCache((cache) -> cache.requestCache(nullRequestCache));
    return http.build();
}

        至此,全文结束。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Security是一个功能强大的身份验证和授权框架,用于保护Java应用程序中的资源。它基于过滤器链的概念来实现安全性。 Spring Security工作原理可以概括如下: 1. 配置:首先,你需要配置Spring Security来定义安全规则和策略。这通常包括配置文件和注解的使用。 2. 过滤器链:Spring Security使用一条过滤器链来拦截请求并执行安全检查。每个过滤器都有特定的功能,例如身份验证、授权等。 3. 身份验证:当用户发送请求时,Spring Security会检查用户的身份验证信息。这可以是基于表单登录、HTTP基本认证、OAuth等不同的机制。 4. 访问控制:一旦用户通过身份验证,Spring Security会根据已定义的规则和策略来授权用户对资源的访问。这可以通过角色、权限等方式进行配置。 5. 安全上下文:Spring Security会创建一个安全上下文对象来保存用户的安全信息,包括认证状态、角色、权限等。这个上下文对象在整个应用程序中都可以访问。 6. 异常处理:如果用户未通过身份验证或未获得授权,Spring Security会引发相应的异常。你可以定义自己的异常处理程序来处理这些异常。 总体而言,Spring Security通过配置、过滤器链、身份验证、访问控制和安全上下文等机制来保护应用程序的安全性。它提供了灵活的配置选项和扩展点,使开发人员能够根据自己的需求来定制和扩展安全功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值