1. 程式人生 > >Spring-Security登入認證授權原理

Spring-Security登入認證授權原理

spring-security原始碼下載地址:

https://github.com/spring-projects/spring-security

Spring-Security原始碼解讀:

1.使用ctrl+shift+n組合鍵查詢UsernamePasswordAuthenticationFilter過濾器,該過濾器是用來處理使用者認證邏輯的,進入後如圖:

(1)可以看到它預設的登入請求url是"/login",並且只允許POST方式的請求

(2)obtainUsername()方法點進去發現它預設是根據引數名為"username"和"password"來獲取使用者名稱和密碼的

(3)通過構造方法例項化一個UsernamePasswordAuthenticationToken物件,此時呼叫的是UsernamePasswordAuthenticationToken的兩個引數的建構函式,如圖:

其中super(null)呼叫的是父類的構造方法,傳入的是許可權集合,因為目前還沒有認證通過,所以不知道有什麼許可權資訊,這裡設定為null,然後將使用者名稱和密碼分別賦值給principal和credentials,同樣因為此時還未進行身份認證,所以setAuthenticated(false)

(4)setDetails(request, authRequest)是將當前的請求資訊設定到UsernamePasswordAuthenticationToken中

(5)通過呼叫getAuthenticationManager()來獲取AuthenticationManager,通過呼叫它的authenticate方法來查詢支援該token(UsernamePasswordAuthenticationToken)認證方式的provider,然後呼叫該provider的authenticate方法進行認證

2.AuthenticationManager是用來管理AuthenticationProvider的介面,通過查詢後進入,然後使用ctrl+H組合鍵檢視它的繼承關係,找到ProviderManager實現類,它實現了AuthenticationManager介面,檢視它的authenticate方法,它裡面有段這樣的程式碼:

for (AuthenticationProvider provider : getProviders()) {
        if (!provider.supports(toTest)) {
            continue;
        }
    ...
    try {
            result = provider.authenticate(authentication);
    ...
    }
}

通過for迴圈遍歷AuthenticationProvider物件的集合,找到支援當前認證方式的AuthenticationProvider,找到之後呼叫該AuthenticationProvider的authenticate方法進行認證處理:

result = provider.authenticate(authentication);

3.AuthenticationProvider介面,就是進行身份認證的介面,它裡面有兩個方法:authenticate認證方法和supports是否支援某種型別token的方法,通過ctrl+h檢視繼承關係,找到AbstractUserDetailsAuthenticationProvider抽象類,它實現了AuthenticationProvider介面,它的supports方法如下:

    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class
            .isAssignableFrom(authentication));
        }

說明它是支援UsernamePasswordAuthenticationToken型別的AuthenticationProvider

再看它的authenticate認證方法,其中有一段這樣的程式碼:

boolean cacheWasUsed = true;
    UserDetails user = this.userCache.getUserFromCache(username);

    if (user == null) {
        cacheWasUsed = false;

        try {
            user = retrieveUser(username,
                    (UsernamePasswordAuthenticationToken) authentication);
        }
    ...
    }

如果從快取中沒有獲取到UserDetails,那麼它呼叫retrieveUser方法來獲取使用者資訊UserDetails,這裡的retrieveUser是抽象方法,等一會我們看它的子類實現。

使用者資訊UserDetails是個介面,我們進入檢視,它包含以下6個介面方法:

Collection<? extends GrantedAuthority> getAuthorities();//獲取許可權集合
String getPassword();  //獲取密碼
String getUsername();   //獲取使用者名稱
boolean isAccountNonExpired(); //賬戶未過期
boolean isAccountNonLocked();   //賬戶未鎖定
boolean isCredentialsNonExpired(); //密碼未過期
boolean isEnabled();    //賬戶可用

檢視它的繼承關係發現User類實現了該介面,並實現了該介面的所有方法

接著AbstractUserDetailsAuthenticationProvider往下看,找到下面的程式碼:

    preAuthenticationChecks.check(user);
    additionalAuthenticationChecks(user,
                (UsernamePasswordAuthenticationToken) authentication);

preAuthenticationChecks預檢查,在最下面的內部類DefaultPreAuthenticationChecks中可以看到,它會檢查上面提到的三個boolean方法,即檢查賬戶未鎖定、賬戶可用、賬戶未過期,如果上面的方法只要有一個返回false,就會丟擲異常,那麼認證就會失敗。

additionalAuthenticationChecks是附加檢查,是個抽象方法,等下看子類的具體實現。

下面還有個postAuthenticationChecks.check(user)後檢查,在最下面的DefaultPostAuthenticationChecks內部類中可以看到,它會檢查密碼未過期,如果為false就會丟擲異常

如果上面的檢查都通過並且沒有異常,表示認證通過,會呼叫下面的方法:

createSuccessAuthentication(principalToReturn, authentication, user);

跟進發現此時通過構造方法例項化物件UsernamePasswordAuthenticationToken時,呼叫的是三個引數的構造方法:

    public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
        Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.credentials = credentials;
    super.setAuthenticated(true); // must use super, as we override
}

此時會呼叫父類的構造方法設定許可權資訊,並呼叫父類的setAuthenticated(true)方法,到這裡就表示認證通過了。

下面我們看看AbstractUserDetailsAuthenticationProvider的子類,同ctrl+h可檢視繼承關係,找到DaoAuthenticationProvider

4.DaoAuthenticationProvider類

(1)檢視additionalAuthenticationChecks附加檢查方法,它主要是檢查使用者密碼的正確性,如果密碼為空或者錯誤都會丟擲異常

(2)獲取使用者資訊UserDetails的retrieveUser方法,主要看下面這段程式碼:

UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);

它是呼叫了getUserDetailsService先獲取到UserDetailsService物件,通過呼叫UserDetailsService物件的loadUserByUsername方法獲取使用者資訊UserDetails

找到UserDetailsService,發現它是一個介面,檢視繼承關係,有很多實現,都是spring-security提供的實現類,並不滿足我們的需要,我們想自己制定獲取使用者資訊的邏輯,所以我們可以實現這個介面。比如從我們的資料庫中查詢使用者資訊

5.SecurityContextPersistenceFilter過濾器

那麼使用者認證成功之後,又是怎麼儲存認證資訊的呢,在下一次請求過來是如何判斷該使用者是否已經認證了呢?

請求進來時會經過SecurityContextPersistenceFilter過濾器,進入SecurityContextPersistenceFilter過濾器並找到以下程式碼:

SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

從session中獲取SecurityContext物件,如果沒有就例項化一個SecurityContext物件

SecurityContextHolder.setContext(contextBeforeChainExecution);

將SecurityContext物件設定到SecurityContextHolder中

chain.doFilter(holder.getRequest(), holder.getResponse());

表示放行,執行下一個過濾器

執行完後面的過濾並經過servlet處理之後,響應給瀏覽器之前再次經過此過濾器。檢視以下程式碼:

SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());

通過SecurityContextHolder獲取SecurityContext物件,然後清除SecurityContext,最後將獲取的SecurityContext物件放入session中

其中SecurityContextHolder是與ThreadLocal繫結的,即本執行緒內所有的方法都可以獲得SecurityContext物件,而SecurityContext物件中包含了Authentication物件,即使用者的認證資訊,spring-security判斷使用者是否認證主要是根據SecurityContext中的Authentication物件來判斷。Authentication物件的詳細資訊如圖:

最後整個過程的流程大致如下圖:


相關推薦

Spring-Security登入認證授權原理

spring-security原始碼下載地址:https://github.com/spring-projects/spring-security Spring-Security原始碼解讀:1.使用ctrl+shift+n組合鍵查詢UsernamePasswordAuthen

Spring Boot 2.X(十八):整合 Spring Security-登入認證和許可權控制

前言 在企業專案開發中,對系統的安全和許可權控制往往是必需的,常見的安全框架有 Spring Security、Apache Shiro 等。本文主要簡單介紹一下 Spring Security,再通過 Spring Boot 整合開一個簡單的示例。 Spring Security 什麼是 Spring Se

Spring Security技術棧開發企業級認證授權(八)Spring Security的基本執行原理與個性化登入實現

正如你可能知道的兩個應用程式的兩個主要區域是“認證”和“授權”(或者訪問控制)。這兩個主要區域是Spring Security的兩個目標。“認證”,是建立一個他宣告的主題的過程(一個“主體”一般是指使用者,裝置或一些可以在你的應用程式中執行動作的其他系統)

Spring Boot後臺腳手架搭建 [五] Spring Security登入實現以及認證過程

Spring Security實現登入spring security的配置    SecurityConfig@Override protected void configure(HttpSecurity http) throws Exception { //跨站請求偽造禁用

訪問專案域彈出瀏覽器原生登入框----Spring Security登陸認證 LDAP認證

springSecurity的登入驗證是由org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter這個過濾器來完成的,在該類的父類AbstractAuthenticationProcessingF

深入Spring Security-獲取認證機制核心原理講解

文/朱季謙 本文基於Springboot+Vue+Spring Security框架而寫的原創筆記,demo程式碼參考《Spring Boot+Spring Cloud+Vue+Element專案實戰:手把手教你開發許可權管理系統》一書。能力有限,存在不足還請指出,本文僅當做學習筆記。   在神祕的

spring security oauth2認證中心 集成zuul網關的代碼分析

負載 很好 結合 gate conf git oauth2 註冊 通過 zuul作為業務網關需要對其內部的服務進行權限控制,采用oauth2的資源服務器集成到zuul中可以很好的保護zuul內部的服務,需要搭建服務註冊中心,認證中心,鑒權中心三大板塊,其中鑒權中心是和zuu

基於spring-security-oauth2搭建授權服務器(一)

常用 遊戲 安全性 獲取 部分 tools token 界面 作者 背景:需要API網關控制權限,單點登陸。 當前關於這方面的系統資料較少,因此大多是找尋網上零散的示例解析,結合官方文檔中的demo再加上源碼跟蹤調試來進行學習與搭建。但由於涉及的知識點較多,且零散示

spring實戰-Spring-security許可權認證白名單

第九篇:spring實戰-Spring-security許可權認證白名單 當我們為程式設定許可權認證時,主要是希望能夠保護需要保護的功能,並不是說所有的功能都需要被保護起來,比如說系統主頁,幫助中心等等 此時我們可以通過白名單的方式,讓某些功能對未登入使用者公開,Spring-secur

Eureka Server 開啟Spring Security Basic認證

文章共 503字,閱讀大約需要 2分鐘 ! 概 述 Eureka Server 在實際使用過程中必須考慮安全問題,比如 未認證的使用者 不允許其隨意呼叫 Eureka Server的 API;還有一個則是 未認證的 Eureka Client 也禁止其註冊到 Eureka Server中來,

spring security登入

form-login是spring security名稱空間配置登入相關資訊的標籤,它包含如下屬性:  1. login-page 自定義登入頁url,預設為/login  2. login-processing-url 登入請求攔截的url,也就是form表單提交時指定的act

ssm下的spring-security登入許可權與角色記錄

配置檔案記錄 <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:b

Spring Security身份認證之UserDetailsService

        之前我們採用了配置檔案的方式從資料庫中讀取使用者進行登入。雖然該方式的靈活性相較於靜態賬號密碼的方式靈活了許多,但是將資料庫的結構暴露在明顯的位置上,絕對不是一個明智的做法。本文通過Java程式碼實現UserDetailsService介面來實現身份認證。 

Spring Security Oauth2 認證(獲取token/重新整理token)流程(password模式)

1.本文介紹的認證流程範圍 本文主要對從使用者發起獲取token的請求(/oauth/token),到請求結束返回token中間經過的幾個關鍵點進行說明。 2.認證會用到的相關請求 注:所有請求均為post請求。 獲取access_token請求(

Spring boot + Spring Security + Thymeleaf 認證失敗返回錯誤資訊

Spring boot +Spring Security + Thymeleaf 認證失敗返回錯誤資訊 Spring boot以其眾多友誼的特性,如零配置、微服務等,吸引了很多的粉絲。而其與Spring Security安全框架的無縫結合,使其具備的安全的特性。在此基礎上

spring security 登入根據使用者角色跳轉到不同的頁面

pring security 做的登入程式,不同角色的使用者登入之後,可能會跳轉到不同的頁面,在預設情況下的配置,都是跳轉到同一個頁面,因為在 form-login 中設定的 default-target-url 就是登入後應該跳轉到的頁面。如何使得不同角色的使用者登入後跳

spring security登入失敗的錯誤提示

這篇文章講得很清楚了,http://forum.springsource.org/showthread.php?96206-How-to-display-error-message-in-spring-security 另外需要解決的是驗證碼問題,可以用filter方式解決

spring security 登入、許可權管理配置

登入流程 1)容器啟動(MySecurityMetadataSource:loadResourceDefine載入系統資源與許可權列表)  2)使用者發出請求  3)過濾器攔截(MySecurityFilter:doFilter)  4)取得請求資源所需許可權(MySe

spring security登入驗證

import com.qingxing.ManagerComplex.api.util.DateUtils; import com.qingxing.ManagerComplex.api.util.LogUtil; import com.qingxing.Man

Spring Security 安全認證簡單入門

廢話不說了,直接上程式碼   看註釋應該丟會吧  到時候改下使用者名稱  和密碼即可第一步:導包  pom.xml<!--安全認證  --><dependency><groupId>org.springframework.security&