Spring-Security框架的实现流程

Spring-Security实现流程

在这里插入图片描述

spring-security入口

DelegatingFilterProxy(Spring-Web) ->FilterChainProxy `(Spring-Security)->

这里看出Spring是通过DelegatingFilterProxy来整合Spring-Security的

一般这个类在我们的web.xml配置中使用的,当我们定义的filter为DelegatingFilterProxy

此时呢,所有的请求filter,都会去容器中找一个叫springsecurityfilterchain的bean来处理。

这里是方便我们去处理web应用,当我们需要一个filter来处理,此时我们只需要在spring相关的配置文件中定义一个bean,id为springSecurityFilterChain ,而在web.xml中写成DelegatingFilterProxy。

特别提示

DelegatingFilterProxy不需要是一个spring 的bean,也就是说在不使用spring容器开发的应用中,可以是有该类。或者说在spring容器还没有初始化的时候,可以使用该类来处理。这也是为什么可以在web.xml中使用该类的原因。

DelegatingFilterProxy的作用

DelegatingFilterProxy 把处理的执行交给了 FilterChainProxy(注意这个类是spring-security中的类,然后会有很多这样的类去做具体的filter操作),这个bean一般使用 springSecurityFilterChain 这个bean id来做配置。

FilterChainProxy这里代理中包含很多的filter(关于spring-security安全认证和权限控制的filters),当然也可以是不同的filter chains,不过一个请求只会被一个filter chain处理,一般是根据请求路径来判断交给那个filter chain处理。
这里就是我们需要关注和定义的filters

SecurityFilterChain接口

spring-security可以有很多SecurityFilterChain,但是最终只有一个会被匹配。

可以用于oauth整合、jwt整合,也可以用于处理不需要安全处理的路径。

也就是说所有的链都必须实现该类

默认的**DefaultSecurityFilterChain**

在这里插入图片描述

一般springboot应用中有6条filter chains,第一个是用来控制静态文件和错误页面的(可以通过配置security.ignored来定义资源路径)。

最后一个filter chain 默认会对 /** 进行控制(包括认证、授权、异常处理、session处理、请求头处理等等)。

默认最后一个chain有11个filters,不过一般我们不需要太关注这些filters。

IgnoredPathsWebSecurityConfigurerAdapter
@Order(SecurityProperties.IGNORED_ORDER)
	private static class IgnoredPathsWebSecurityConfigurerAdapter
			implements WebSecurityConfigurer<WebSecurity> {

默认的springBoot security项目中,其实对静态资源的处理和error路径的处理,使用的同一个filter chain :IgnoredPathsWebSecurityConfigurerAdapter,它的order 为最高的。HIGHEST_PRECEDENCE = Integer.MIN_VALUE,所以这是一个回去匹配的filter chain。

在spring-security中新增一个filter chain(其实也是覆盖的意思,比如原来的filter针对的是 /** ,这里我们写了一个/foo/** ,此时如果请求是/foo/,则只会经过该filter chain;如果是其他的请求,才会使用原来默认的chain ):

@Configuration@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  }}

注意
如果想在spring-security 的chain使用filter Bean,

1.不要通过使用@bean 方式去添加

2.如果使用FilterRegistrationBean注册filter为一个Bean,则需要显示设置其不被容器加载。

因为这两种方式都会将filter应用于整个web 容器中。

而添加自定义的security filter,需要通过

WebSecurityConfigurerAdapter#configure()

WebSecurityConfigurerAdapter#init()

开始认证处理

其实这里是认证处理的发起Filter,当用户第一次从浏览器访问受限资源时,因为其他认证Filter只对自己关注的AuthenticationToken进行处理,也就是说第一次访问时,这些Filter是去处理的,只有这个Filter发现如果用户没有进行认证,则进行相应的处理。比如:重定向到登入页面。

处理流程

在这里插入图片描述

The ExceptionTranslationFilterallows translation of AccessDeniedException and AuthenticationExceptioninto HTTP responses.

  • First, the ExceptionTranslationFilter invokes FilterChain.doFilter(request, response) to invoke the rest of the application.
  • If the user is not authenticated or it is an AuthenticationException, then Start Authentication.
    • The SecurityContextHolder is cleared out
    • The HttpServletRequest is saved in the RequestCache. When the user successfully authenticates, the RequestCache is used to replay the original request.
    • The AuthenticationEntryPoint is used to request credentials from the client. For example, it might redirect to a login page or send a WWW-Authenticate header.
  • Otherwise if it is an AccessDeniedException, then Access Denied. The AccessDeniedHandler is invoked to handle access denied.
源码展示
try {
    filterChain.doFilter(request, response); 
} catch (AccessDeniedException | AuthenticationException e) {
    if (!authenticated || e instanceof AuthenticationException) {
        startAuthentication(); 
    } else {
        accessDenied(); 
    }
}

开始认证处理,从AuthenticationEntryPoint开始,然后调用org.springframework.security.web.AuthenticationEntryPoint#commence,具体的实现类来实现如何进行认证。

是否需要处理认证

当用户提交认证信息后,比如输入用户名\密码之后。

AbstractAuthenticationProcessingFilter

该类将会判断请求是否需要认证或者是本类实现类应该处理的认证类型。

如果是,则进行具体的认证信息判断。

源码展示

这里以 UsernamePasswordAuthenticationFilter 为例:

public class UsernamePasswordAuthenticationFilter extends
      AbstractAuthenticationProcessingFilter {
	//这里开始尝试进行认证信息判断
   public Authentication attemptAuthentication(HttpServletRequest request,
         HttpServletResponse response) throws AuthenticationException {
     
      String username = obtainUsername(request);
      String password = obtainPassword(request);
      UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
            username, password);
      // Allow subclasses to set the "details" property
      setDetails(request, authRequest);
       //最终调用authenticationManager去进行认证
      return this.getAuthenticationManager().authenticate(authRequest);
   }
}
真正处理用户认证信息判断
认证判断

具体的认证判断由 AuthenticationProvider 的实现类来判断。

如之前分析,一个AuthenticationManger可以有多个AuthenticationProvider,每个都可以处理或者处理不了,只要有一个能判断即可,或者都判断不了,还可以通过 ParentAuthenticationManager来兜底。

认证处理的结果

三种情况:

  • 成功
  • 不能决定
  • 异常

如果返回认证异常,我们可以捕获后跳转到认证页面,比如登入页面,或者返回认证错误页面,在接口调用时,可以返回401响应等等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值