我覺得我懂了系列之SpringSecurity(上)

  • 權限設計

對於一個完善的系統,使用會有不少人使用:最起碼也會包含用戶端和後臺管理端兩個角色,固然隨着業務不斷複雜,確定會產生更多的角色,這些角色被賦予不一樣的權限,只能操做系統中的某一部分功能,而後全部角色一塊兒來操做各自的模塊,整個系統才能處於一個正常的活躍狀態。 對於一個系統的登陸方式,從帳號密碼登陸,郵箱密碼登錄,到很是方便的第三方登陸方式:好比掘金的第三方登陸就使用了:微信、GitHub、微博。應該是能夠更加方便的引流吧,去除繁瑣的註冊流程。 除此以外,登陸系統的設計還包含在一個分佈式系統中的單點登陸SSO,使用CAS進行處理,還有jwt等等這些均可以集成在SpringSecurity中,最近連續看了好幾天的Security源碼(以前粗略的看過一遍,基本沒理解),發現好複雜啊,好繞,功能強大勢必會致使複雜的配置,因此在有些場景下使用就會覺着,可是權限設計又是每個系統都須要的,因此決定在這裏仔細縷一縷。html

  • Spring Security 源碼訪問認證流程分析

從listener-filter-servlet中的filter提及,security的入口實際上是filter的FilterChain中的一個filter。java

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.react

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.web

先來看一下通常都有哪些filter,以下圖所示,其中有些是我引入Actuator監控模塊加入的,先不要care,下次單獨說一下他是幹嗎的spring

其中有個filter:DelegatingFilterProxy,這是一個代理,那麼代理的是誰呢?內部持有的FilterChainProxy,它作該過濾器應該作的事情,那麼這個過濾器幹嗎了呢?咱們須要瞭解一個FilterChainProxy這個類(👇),這個就是咱們要security的入口,而後下面咱們從這個入口開始一點一點的分析。express

FilterChainProxy 介紹安全

SecurityFilterChain 介紹微信

首先,在上面介紹中說到filterChainProxy內部的List<SecurityFilterChain> filterChains,須要從這個過濾器鏈的集合中匹配出當前請求的那個過濾器鏈,有個關鍵:RequestMatcher(👇),而後從將匹配到的securityFilterChain中的filter集合拿出來,便開始了進行了過濾,以下圖所示分佈式

RequestMatcher 介紹ide

經過下圖看下這些默認過濾器的功能,沒有詳細看過,後續再談:

咱們着重分析一下: UsernamePasswordAuthenticationFilter這個類就是驗證的關鍵, 第一步:調用父抽象類的doFilter方法:

第二步:調用子類實現的attemptAuthentication方法:

第三步:認證開始: 抽象接口:AuthenticationManager,方法:authenticate(Authentication authentication) 一般使用實現 ProviderManager,它持有一個List providers,這些provider提供了不一樣的認證方式,能夠自定義 AuthenticationProvider進行認證

咱們來看一下這些authenticationProvider都是幹嗎的

DaoAuthenticationProvider:數據訪問認證方式,也就是說能夠從不一樣的數據源來進行認證, 從上圖中也能夠看到父類 AbstractUserDetailsAuthenticationProvider,提供入口authenticate()方法, 而後定義一些抽象方法,子類去實現具體的邏輯,又是模板模式的體現,在 DaoAuthenticationProvider中有個很重要的屬性: UserDetailsService,則會個接口裏面只有一個方法: loadUserByUsername,而後不一樣的服務能夠採起不一樣的策略來實現,對,這裏我感受就是一個策略模式,

  • Spring Security 源碼訪問受權流程分析

FilterSecurityInterceptor 感受也很繞,須要看下那個投票究竟是幹嗎的, 核心:invoke()方法

beforeInvocation()主要流程:

this.accessDecisionManager.decide(authenticated, object, attributes);
//主要是基於AccessDecisionVoter的一個投票過程
//在已經確保用戶經過了認證,如今基於登陸的當前用戶信息,和目標資源的安全配置屬性
//進行相應的權限檢查,若是檢查失敗,則拋出相應的異常 AccessDeniedException
複製代碼

投票的的經過策略:

  • 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,\
複製代碼

說一個主要的自動配置:

而後再上圖最右邊開始裏面開始加載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;
}
複製代碼

繼承實現:

build的統一模板流程:

再看一下 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;
}
複製代碼

繼承實現:

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的構建過程:

固然,還差了不少內容:如何配置,自定義拓展,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…

相關文章
相關標籤/搜索