转载

我以为我懂了系列之SpringSecurity(上)

对于一个完善的系统,使用会有很多人使用:最起码也会包含用户端和后台管理端两个角色,当然随着业务不断复杂,肯定会产生更多的角色,这些角色被赋予不同的权限,只能操作系统中的某一部分功能,然后所有角色一起来操作各自的模块,整个系统才能处于一个正常的活跃状态。 对于一个系统的登录方式,从账号密码登录,邮箱密码登陆,到非常方便的第三方登录方式:比如掘金的第三方登录就使用了:微信、GitHub、微博。应该是可以更加方便的引流吧,去除繁琐的注册流程。 除此之外,登录系统的设计还包含在一个分布式系统中的单点登录SSO,使用CAS进行处理,还有jwt等等这些都可以集成在SpringSecurity中,最近连续看了好几天的Security源码(之前粗略的看过一遍,基本没理解),发现好复杂啊,好绕,功能强大势必会导致复杂的配置,所以在有些场景下使用就会觉着 ,但是权限设计又是每一个系统都需要的,所以决定在这里仔细缕一缕。

  • Spring Security 源码访问认证流程分析

从listener-filter-servlet中的filter说起,security的入口其实是filter的 FilterChain 中的一个filter。

FilterChain: is an object provided by the servlet container to the developer giving a view into the invocation chain of a filtered request for a resource.Filters use the FilterChain to invoke the next filter in the chain, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain.
ApplicationFilterChain: Implementation of FilterChain used to manage the execution of a set of filters for a particular request. When the set of defined filters has all beenexecuted, the next call to doFilter() will execute the servlet's service() method itself.

先来看一下一般都有哪些filter,如下图所示,其中有些是我引入Actuator监控模块加入的,先不要care,下次单独说一下他是干嘛的

我以为我懂了系列之SpringSecurity(上)

其中有个filter:DelegatingFilterProxy,这是一个代理,那么代理的是谁呢?内部持有的FilterChainProxy,它做该过滤器应该做的事情,那么这个过滤器干嘛了呢?我们需要了解一个FilterChainProxy这个类(:point_down:),这个就是我们要security的入口,然后下面我们从这个入口开始一点一点的分析。

FilterChainProxy 介绍

SecurityFilterChain 介绍

首先,在上面介绍中说到filterChainProxy内部的 List<SecurityFilterChain> filterChains ,需要从这个过滤器链的集合中匹配出当前请求的那个过滤器链,有个关键:RequestMatcher(:point_down:),然后从将匹配到的securityFilterChain中的filter集合拿出来,便开始了进行了过滤,如下图所示

RequestMatcher 介绍

我以为我懂了系列之SpringSecurity(上)

通过下图看下这些默认过滤器的功能,没有详细看过,后续再谈:

我以为我懂了系列之SpringSecurity(上)
我们着重分析一下: UsernamePasswordAuthenticationFilter

这个类就是验证的关键, 第一步:调用父抽象类的doFilter方法:

我以为我懂了系列之SpringSecurity(上)

第二步:调用子类实现的attemptAuthentication方法:

我以为我懂了系列之SpringSecurity(上)
第三步:认证开始: 抽象接口:AuthenticationManager,方法:authenticate(Authentication authentication) 通常使用实现 ProviderManager ,它持有一个List providers,这些provider提供了不同的认证方式,可以自定义 AuthenticationProvider

进行认证

我以为我懂了系列之SpringSecurity(上)
我以为我懂了系列之SpringSecurity(上)

我们来看一下这些authenticationProvider都是干嘛的

我以为我懂了系列之SpringSecurity(上)
DaoAuthenticationProvider :数据访问认证方式,也就是说可以从不同的数据源来进行认证, 从上图中也可以看到父类 AbstractUserDetailsAuthenticationProvider ,提供入口authenticate()方法, 然后定义一些抽象方法,子类去实现具体的逻辑,又是模板模式的体现,在 DaoAuthenticationProvider 中有个很重要的属性: UserDetailsService ,则会个接口里面只有一个方法: loadUserByUsername

,然后不同的服务可以采取不同的策略来实现,对,这里我感觉就是一个策略模式,

我以为我懂了系列之SpringSecurity(上)
  • Spring Security 源码访问授权流程分析

FilterSecurityInterceptor 感觉也很绕,需要看下那个投票到底是干嘛的, 核心:invoke()方法

我以为我懂了系列之SpringSecurity(上)

beforeInvocation()主要流程:

this.accessDecisionManager.decide(authenticated, object, attributes);
//主要是基于AccessDecisionVoter的一个投票过程
//在已经确保用户通过了认证,现在基于登录的当前用户信息,和目标资源的安全配置属性
//进行相应的权限检查,如果检查失败,则抛出相应的异常 AccessDeniedException
复制代码
我以为我懂了系列之SpringSecurity(上)

投票的的通过策略:

  • 1.AffirmativeBased-任意1个通过授权成功 Simple concrete implementation of AccessDecisionManager that grants access if any AccessDecisionVoter returns an affirmative response.
  • 2.ConsensusBased-部分通过授权成功 "Consensus" here means majority-rule (ignoring abstains) rather than unanimous agreement (ignoring abstains).
  • 3.UnanimousBased-全部通过授权成功 Simple concrete implementation of AccessDecisionManager that requires all voters to abstain or grant access. 扩展点:
    1. securityMetadataSource 获取安全的元数据(初始化的时候将我们的配置加载进去)
    1. AccessDecisionManager
    1. AccessDecisionVoter 涉及到各种expressionHandle进行match决定投出什么样的票
  • Spring Security 初始化分析(配置如何生效,如何配置)

对于SpringBoot项目进行分析,使用SpringBoot之后最强大的功能便是自动配置,引入security的stater之后,什么都不用干,访问我们的之前的controller接口,就发现已经被保护起来,原因就是这些自动引入的以及通过它们又间接引入的配置:

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,/
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,/
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,/
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,/
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,/
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,/
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,/
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,/
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,/
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,/
复制代码

说一个主要的自动配置:

我以为我懂了系列之SpringSecurity(上)

然后再上图最右边开始里面开始加载webSecurity等一系列的配置; 接下来我们先来分析一下security配置涉及的组件, 我们从SecurityBuilder说起,看到这个想到是一个建造者模式,这是一个高度抽象的接口:

/**
 * Interface for building an Object
 * @param <O> The type of the Object being built
 */
public interface SecurityBuilder<O> {
	/**
	 * Builds the object and returns it or null.
	 * @return the Object to be built or null if the implementation allows it.
	 * @throws Exception if an error occurred when building the Object
	 */
	O build() throws Exception;
}
复制代码

继承实现:

我以为我懂了系列之SpringSecurity(上)

build的统一模板流程:

我以为我懂了系列之SpringSecurity(上)

再看一下 SecurityConfigurer:

/**
 * Allows for configuring a {@link SecurityBuilder}. All {@link SecurityConfigurer} first
 * have their {@link #init(SecurityBuilder)} method invoked. After all
 * {@link #init(SecurityBuilder)} methods have been invoked, each
 * {@link #configure(SecurityBuilder)} method is invoked. 
 * @param <O> The object being built by the {@link SecurityBuilder} 
 * @param <B> The {@link SecurityBuilder} that builds objects of type O. This is also the
 * {@link SecurityBuilder} that is being configured.
 */
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
	/**
	 * Initialize the {@link SecurityBuilder}. Here only shared state should be created
	 * and modified, but not properties on the {@link SecurityBuilder} used for building
	 * the object. This ensures that the {@link #configure(SecurityBuilder)} method uses
	 * the correct shared objects when building.
	 * @param builder
	 * @throws Exception
	 */
	void init(B builder) throws Exception;
	/**
	 * Configure the {@link SecurityBuilder} by setting the necessary properties on the
	 * {@link SecurityBuilder}.
	 * @param builder
	 * @throws Exception
	 */
	void configure(B builder) throws Exception;
}
复制代码

继承实现:

我以为我懂了系列之SpringSecurity(上)
SecurityBuilder 是用来构建 O

这个类型的对象的; SecurityConfigurer 是用来对不同的build过程中的属性进行配置; 这里面包含有众多的类,我们说一些重要的:

  • HttpSecurity:创建的对象类型为DefaultSecurityFilterChain
  • WebSecurity:create the FilterChainProxy known as the Spring Security Filter Chain (springSecurityFilterChain).
  • WebSecurityConfigurer:Allows customization to the {@link WebSecurity}.
  • WebSecurityConfigurerAdapter:Provides a convenient base class for creating a WebSecurityConfigurer instance.
  • DefaultSecurityFilterChain:是SecurityFilterChain的默认实现,提供两个功能: url匹配filter集合处理 ,在springSecurityFilterChain中可以创建一个或者多个SecurityFilterChain,并且根据SecurityFilterChain提供的requestMatcher来决定使用哪个SecurityFilterChain中的filter来处理当前请求,相当于于一个代理; httpSecurity的构建过程:
我以为我懂了系列之SpringSecurity(上)

当然,还差了很多内容:如何配置,自定义拓展,cas,jwt,第三方登录等,我觉着这些东西,第一是知道一些使用规范流程,比如:cas单点登录的流程,Oauth2.0的流程,然后加上对整个security是如何进行初始化我们的配置,如何进行认证和授权的流程的熟悉,将这些内容添加进来也就变得会容易一些,当然实际操作的过程中肯定会有各种问题,一个一个解决就完事了。

参考:

www.shangyang.me/categories/… www.jianshu.com/u/fb66b7412… zhuanlan.zhihu.com/c_111502114… docs.spring.io/spring-secu…

原文  https://juejin.im/post/5d4bce2ce51d4561c273a673
正文到此结束
Loading...