简单分析SpringSecurity的流程

105 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

背景 最近项目用到了SpringSecurity,本人以前一直觉得很难理解,正好趁此机会将这块重新理解梳理下。话不多说,直接开干。 搭建环境

  • 引入springboot
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.0</version>
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 简单写一个controller
@RestController
@RequestMapping(value = "user")
public class UserController {

    @GetMapping("userPage")
    public Response userPage() {
        return Response.succeed();
    }

}

直接启动起来,访问此接口发现被拦截,跳转到了默认的登录页,输入user和默认的密码之后,可以正常访问到userPage接口并正常返回。那这些都是怎样实现的呢

分析 细心的同学可以看到服务启动的时候打印了一行日志

o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with。。。。。。。。。

这段日志的意思是请求将会经过如下默认的安全过滤链,即

org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1fd9893c, 
org.springframework.security.web.context.SecurityContextPersistenceFilter@41ad373,
org.springframework.security.web.header.HeaderWriterFilter@6ca8fcf3, 
org.springframework.security.web.csrf.CsrfFilter@4462efe1, 
org.springframework.security.web.authentication.logout.LogoutFilter@3119cf6f, 
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@76a14c8d,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@6dc9da2d, 
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@1b2df3aa, 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@7165d530, 
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@177c41d7, 
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@d2291de, 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@44be69aa, 
org.springframework.security.web.session.SessionManagementFilter@66933239, 
org.springframework.security.web.access.ExceptionTranslationFilter@3d1f558a, 
org.springframework.security.web.access.intercept.FilterSecurityInterceptor@ae73c80

今天我们只分析关键的一个过滤器今天我们只分析关键的一个过滤器UsernamePasswordAuthenticationFilter

我们看到它的源码有一个attemptAuthentication方法,这个就是我们登录接口验证的方法,那我们一步步看到它的调用链可以用以下图来说明: attemptAuthentication.png

我们能看到最后是UserDetailsService的实现类的loadUserByUsername,那使用者实现的UserDetailsService又是在哪里set进来的呢?我们看到InitializeUserDetailsBeanManagerConfigurer中有一个set方法

image.png 即可知此UserDetailsService实现类是在初始化的时候set进去的。如此整个链路就通了!豁然开朗。

那密码的校验又是在哪里呢?我们跟着代码能看到能看到密码的校验是在DaoAuthenticationProvider

image.png

总结 今天只是简单分析了一个filter的大致流程,后续有空两仔细分析每个filter的功能,敬请期待。