由浅入深理解SpringSecurityOauth2框架原理

2,730 阅读8分钟

克服自己消极的、钻牛角尖的扭曲的思想方式,便能增加效率,提高自尊心

1.基础知识点Security组件的认识Filter-ServletSecurity原理代码层面的集成:WebSecurityConfiguration2.Security 执行流程图3.Security Oauth2 原理组件认知TokenEndpoint:TokenGranter:TokenServices :代码层面的认知:4.Security Oauth2 流程图token获取流程图接口请求流程图5.总结

1.基础知识点

为了理解Security Oauth2 我们要先理解Security ;理解Security ,我们需要先做一些Security组件等基础认识的认识。

Security组件的认识

  • SecurityContextHolder:用来存储安全上下文信息,Spring Security 的校验之后,验证信息存储在SecurityContext

  • Authentication: 在Security领域,用户密码等不叫做用户密码,叫做Authentication。Authentication 在 spring security 中是最高级别的身份 / 认证的抽象。 在进入Security领域前,得把信息封装成Authentication.(如果用一成语来形容,就是入乡随俗),例如我们常用的[clientId,clientSecret ] [username,password]都可以封装成一个(Authentication)UsernamePasswordAuthenticationToken

  • AuthenticationManager: 从组件层面讲,此组件是用来校验Authentication,常见实现类有ProviderManager。但是从代码层面,ProviderManager 将校验的工作交给了另一个组件AuthenticationProvider来完成的。ProviderManager 中维护一个List,通过遍历找到支持当前Authentication认证的AuthenticationProvider,交给其进行认证。(这样看AuthenticationManager可以看做是大总管

  • AuthenticationProvider: 就是上面说的代码层面真正Authentication进行校验的组件。常见的AuthenticationProvider有

    (1.DaoAuthenticationProvider: Dao式认证Provider ,从数据库中取出信息与提交的信息进行比对,完成认证。

    (2. AnonymousAuthenticationProvider: 匿名认证Provider

  • UserDetails : 理解UserDetails,我们可以对比Authentication来理解, Authentication是来自用户提交的数据封装,UserDetails 是从数据层获取的用户信息封装。

  • UserDetailsServiceDaoAuthenticationProvider认证器从数据库层取数据是通过UserDetailsService 完成的,取到的是UserDetails 。常见的UserDetailsService

    (1.JdbcDaoImpl

    (2.ClientDetailsUserDetailsService: 查询[clientId,clientSecret ]形式的UserDetails

Filter-Servlet

我们都知道请求经过Filter链到Servlet

过程看起来是这样

在这里插入图片描述
在这里插入图片描述

Security原理

牢记,Spring Security在web应用中,是通过filter 介入的。

为了介入到主体ApplicationFilterChain中,这里要介绍一个特殊的Filter ,

DelegatingFilterProxy:

​ 这个Filter很有意思,他内部有一个Filter delegate属性 ,用来代理另一个Filter。当请求执行到DelegatingFilterProxy时,会调用delegate 这个Filter 。DelegatingFilterProxy可以看做是一个可以让Filter链拐弯的 Filter

在这里插入图片描述
在这里插入图片描述

FilterChainProxy:

​ 也是一个Filter , Security就是通过把他设置到DelegatingFilterProxy.delegate属性上来介入了主体FilterChain .但是从他名称来看他本身也是一个代理性质的FIlter

​ 他内部维护了一个List<SecurityFilterChain> filterChains来表示不同权限的url对应的不同的过滤器链 ,但是一次请求最多只有一个SpringSecurityFilterChain链。

SpringSecurityFilterChain

​ FilterChainProxy遍历List<SecurityFilterChain> filterChains匹配到一个适用于当前请求的SecurityFilterChain然后就是链式调用了。

Security 常见Filter

  • SecurityContextPersistenceFilter: 位于SecurityFilterChain的顶端。以前我们使用session来存储用户信息,用了Security框架后,用户登录一次,后续通过sessionId 来识别,用户信息存放到SecurityContextHolder中,这个放入的过程就是SecurityContextPersistenceFilter完成的。SecurityContextPersistenceFilter的主要工作创建 SecurityContext 安全上下文信息和请求结束时清空 SecurityContextHolder(用了try,finally组合)

  • UsernamePasswordAuthenticationFilter:表单认证是最常用的一个认证方式,允许表单输入用户名和密码进行登录。他会先将 [username,password]封装成Authentication然后交给authenticationManager 认证,authenticationManager 会选择一个provider ,通过UserDetailsService从redis获取mysql等数据层面获得存储用户信息的数据的UserDetail与Authentication 进行对比。认证成功

  • ExceptionTranslationFilter: 异常转换过滤器位于整个 springSecurityFilterChain 的后方,主要处理两大异常,AccessDeniedException 访问异常和 AuthenticationException 认证异常。根据配置和异常类型,会选择跳转到登录页面,或者404 ,405页面。

代码层面的集成:

代码中使用Security 最重要的是@EnableWebSecurity ,这是代码集成Security的重要注解,我们来看看

Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
        SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
    boolean debug() default false;
}
---
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}

@EnableWebSecurity注解的工作就是激活三个类

  • SpringWebMvcImportSelector: 判断当前的环境是否包含 springmvc
  • WebSecurityConfiguration: 是用来配置 web 安全的
  • AuthenticationConfiguration: 配置认证相关的核心类,主要负责生成全局的身份认证管理者 AuthenticationManager

最重要的就是WebSecurityConfiguration

WebSecurityConfiguration

在这之前介绍一个阅读Spring相关框架的源码技巧

xxConfiguration: 这种格式的配置文件,我们可以看做是一个bean.xml文件,对容器输出Bean

xxConfigurer: 这种格式的配置文件,通常是要被xxConfiguration获取到。xxConfiguration文件从xxConfigurer中提取配置,统一到xxConfiguration中处理。

一句话总结:xxConfiguration会搜集N个相关的xxConfigurer到本类中解析他们,统一成一个xxConfiguration配置文件对容器输出Bean.

好,下面我看看WebSecurityConfiguration

public class WebSecurityConfiguration implements ImportAwareBeanClassLoaderAware {

    //搜集SecurityConfigurer到本类中,做集中解析。
    private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers

     //输出springSecurityFilterChain bean
    @Bean(name = "springSecurityFilterChain";)
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();//构建FilterChainProxy
    }
}

两个重要点:

  • 搜集相关的SecurityConfigurer: 我们集成security时,通常会继承WebSecurityConfigurerAdapter做安全配置,WebSecurityConfigurerAdapter本身实现了SecurityConfigurer,这样们的配置信息会被解析到WebSecurityConfiguration配置类中,作用到security中。所以这就是为啥我们要实现一个WebSecurityConfigurerAdapter来配置安全策略的原因。
  • 输出(FilterChainProxy)springSecurityFilterChain bean : 这样就算是在代码层面与主题FilterChain对接上了。(springSecurityFilterChain的创建过程有兴趣的可以跟下代码)

WebSecurityConfigurerAdapter适配器模式的运用,使我们可以选择性的实现部分配置。

2.Security 执行流程图

在此理论知识,代码知识的基础上,我直接贴出流程图

在这里插入图片描述
在这里插入图片描述

3.Security Oauth2 原理

看完了Security的原理,我们在看看oauth2的原理。

  • Security Oauth2 如何架设在Security框架之上?

  • Security Oauth2 又发生了哪些变化呢?

  • Oauth2的四种认证方式是如何实现的?

带着这些疑问,我们还是从组件的认识到执行流程图

组件认知

TokenEndpoint:

理解为一个Controller ,/oauth/token接口就是在这里。 提到Controller,我们就知道,这就是业务逻辑处理地方,也就是Oauth逻辑处理的地方。

TokenGranter:

组件层面意思是令牌授予者,Oauth2规范的实现就是此组件实现的

在这里插入图片描述
在这里插入图片描述
TokenServices :

定义了对Token的一些操作,创建,获取,刷新。我们把他理解为Sevevice层

  • AuthorizationServerTokenServices : 授权服务器端用到的tokenSerrvices
  • ResourceServerTokenServices: 资源服务器端的tokenservices

这样这三个组件的关系体系就出来:

请求到Controller ,交给TokenGranter进行授权,TokenGranter授权过程中调用TokenServices 生成token。

代码层面的认知:

集成oauth2,我们会多出两个配置类来,为什么???

//权限服务器配置
@Configuration
@EnableAuthorizationServer
protected static class MyAuthorizationServerConfiguration extends  AuthorizationServerConfigurerAdapter {
}

//@EnableAuthorizationServer注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
public @interface EnableAuthorizationServer {

}


//资源服务器配置
@Configuration
@EnableResourceServer
protected static class MyResourceServerConfiguration extends
    ResourceServerConfigurerAdapter 
{

}

//@EnableResourceServer注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ResourceServerConfiguration.class)
public @interface EnableResourceServer {

}

权限服务器配置:

@EnableAuthorizationServer注解:此注解主要是激活两个配置类

  • AuthorizationServerEndpointsConfiguration : 配置TokenEndpoint 等Controller类,也就是注册Controller式Bean,例如/oauth/token接口
  • AuthorizationServerSecurityConfiguration: 间接实现了SecurityConfigurer接口。SecurityConfigurer接口在上面说过, 会在启用Security时,被WebSecurityConfiguration配置类搜集解析。这样Oauth2的配置与Security配置体系关联起来了。

MyAuthorizationServerConfiguration:继承于AuthorizationServerConfigurerAdapter,间接继承了AuthorizationServerConfigurer。 看到AuthorizationServerConfigurer ,可以想象应该有个xxxConfiguration的配置文件来解析他。是的,他就是被**AuthorizationServerSecurityConfiguration**搜集解析的. 而AuthorizationServerSecurityConfiguration会被WebSecurityConfiguration配置类搜集。这样我们自定义的配置就这样跟Security配置体系关联起来

public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();
}  

资源服务器配置:

EnableResourceServer注解:主要是激活ResourceServerConfiguration类

  • ResourceServerConfiguration : 也间接实现了SecurityConfigurer接口,也就是说也会被WebSecurityConfiguration配置类搜集解析

MyResourceServerConfiguration: 自定义配置。实现了ResourceServerConfigurer 接口,他会被ResourceServerConfiguration配置类搜集解析,最终也是会进入WebSecurityConfiguration配置类

到此我们可以看出,集成Oauth2时,看似多出的两个配置类,其实还是在间接配置Security ,最终都会在Security框架体系内生效。 也说明了Oauth2框架就是架设在Security框架之上。

4.Security Oauth2 流程图

token获取流程图

在这里插入图片描述
在这里插入图片描述

接口请求流程图

在这里插入图片描述
在这里插入图片描述

5.总结

  • Spring security 在web应用中是基于Filter的
  • Spring security Oauth2 基于 Security 框架添加认证模式的逻辑

如果本文任何错误,请批评指教,不胜感激 !
如果文章哪些点不懂,可以联系我交流学习!

微信公众号:源码行动
享学源码,行动起来,来源码行动