由浅入深理解SpringSecurityOauth2框架原理

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 由浅入深理解SpringSecurityOauth2框架原理

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

过程看起来是这样


image.png

image.png


Security原理

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

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


DelegatingFilterProxy:  

                   这个Filter很有意思,他内部有一个Filter delegate属性 ,用来代理另一个Filter。当请求执行到DelegatingFilterProxy时,会调用delegate 这个Filter 。


DelegatingFilterProxy可以看做是一个可以让Filter链拐弯的 Filter



image.png


FilterChainProxy:  

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

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

SpringSecurityFilterChain

               FilterChainProxy遍历List 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 ImportAware, BeanClassLoaderAware {
    //搜集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 执行流程图


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

image.png


3.Security Oauth2 原理


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

  • Security Oauth2 如何架设在Security框架之上?
  • Security Oauth2 又发生了哪些变化呢?
  • Oauth2的四种认证方式是如何实现的?

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


组件认知

TokenEndpoint:

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


TokenGranter:

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

image.png


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获取流程图

image.png


接口请求流程图

image.png


5.总结


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


相关文章
|
4月前
|
安全 Java 数据库
SpingSecurity框架重要知识点(理解)
SpingSecurity框架重要知识点(理解)
61 1
|
4月前
|
存储 关系型数据库 MySQL
由浅入深:数据库编程概念与实战
由浅入深:数据库编程概念与实战
164 1
|
JavaScript 前端开发
JavaScriptDOM编程(基础&进阶)2
JavaScriptDOM编程(基础&进阶)2
45 0
|
JavaScript 前端开发
JavaScriptDOM编程(基础&进阶)3
JavaScriptDOM编程(基础&进阶)3
48 0
|
XML 移动开发 JavaScript
JavaScriptDOM编程(基础&进阶)1
JavaScriptDOM编程(基础&进阶)1
49 0
|
11天前
|
SQL 安全 PHP
深入浅出PHP编程:从基础到实战
在数字化时代的浪潮中,掌握PHP编程技能成为许多开发者的必修课。本文旨在通过浅显易懂的语言,带领读者走进PHP的世界,不仅介绍PHP的基础语法和核心概念,还将通过实际案例,展示如何将理论知识应用到项目开发中。无论你是编程新手还是希望深化PHP技能的开发者,这篇文章都将为你提供有价值的指导和灵感。让我们一起探索PHP的魅力,开启编程之旅吧!
|
3月前
|
机器学习/深度学习 算法 Python
【算法】深入浅出爬山算法:原理、实现与应用
【算法】深入浅出爬山算法:原理、实现与应用
81 3
|
4月前
|
存储 移动开发 前端开发
【Uniapp 专栏】Uniapp 架构设计与原理探究
【5月更文挑战第12天】Uniapp是一款用于跨平台移动应用开发的框架,以其高效性和灵活性脱颖而出。它基于HTML、CSS和Vue.js构建视图层,JavaScript处理逻辑层,管理数据层,实现统一编码并支持原生插件扩展。通过抽象平台特性,开发者能专注于业务逻辑,提高开发效率。尽管存在兼容性和复杂性挑战,但深入理解其架构设计与原理将助力开发者创建高质量的跨平台应用。随着技术进步,Uniapp将继续在移动开发领域扮演重要角色。
147 1
【Uniapp 专栏】Uniapp 架构设计与原理探究
|
4月前
|
安全 Java 开发者
Java编程:深入探索其原理、特性与实战代码
Java编程:深入探索其原理、特性与实战代码
34 1
|
4月前
|
存储 消息中间件 负载均衡
图解 | 搞定分布式,程序员进阶之路
图解 | 搞定分布式,程序员进阶之路
85 1