一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringSecurity認證流程詳解

SpringSecurity認證流程詳解

2021-05-05 11:07whyalwaysmea Java教程

這篇文章主要介紹了SpringSecurity認證流程詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

springsecurity基本原理

在之前的文章《springboot + spring security 基本使用及個性化登錄配置》中對springsecurity進行了簡單的使用介紹,基本上都是對于接口的介紹以及功能的實現。 這一篇文章嘗試從源碼的角度來上對用戶認證流程做一個簡單的分析。
在具體分析之前,我們可以先看看springsecurity的大概原理:

SpringSecurity認證流程詳解

springsecurity基本原理

其實比較簡單,主要是通過一系列的filter對請求進行攔截處理。

認證處理流程說明

我們直接來看usernamepasswordauthenticationfilter類,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class usernamepasswordauthenticationfilter extends abstractauthenticationprocessingfilter
  // 登錄請求認證
  public authentication attemptauthentication(httpservletrequest request, httpservletresponse response) throws authenticationexception {
    // 判斷是否是post請求
    if (this.postonly && !request.getmethod().equals("post")) {
      throw new authenticationserviceexception("authentication method not supported: " + request.getmethod());
    } else {
      // 獲取用戶,密碼
      string username = this.obtainusername(request);
      string password = this.obtainpassword(request);
      if (username == null) {
        username = "";
      }
 
      if (password == null) {
        password = "";
      }
 
      username = username.trim();
      // 生成token,
      usernamepasswordauthenticationtoken authrequest = new usernamepasswordauthenticationtoken(username, password);
      this.setdetails(request, authrequest);
      // 進一步驗證
      return this.getauthenticationmanager().authenticate(authrequest);
    }
  }
}

attemptauthentication方法中,主要是進行username和password請求值的獲取,然后再生成一個usernamepasswordauthenticationtoken 對象,進行進一步的驗證。

不過我們可以先看看usernamepasswordauthenticationtoken 的構造方法

?
1
2
3
4
5
6
7
8
public usernamepasswordauthenticationtoken(object principal, object credentials) {
  // 設置空的權限
  super((collection)null);
  this.principal = principal;
  this.credentials = credentials;
  // 設置是否通過了校驗
  this.setauthenticated(false);
}

其實usernamepasswordauthenticationtoken是繼承于authentication,該對象在上一篇文章中有提到過,它是處理登錄成功回調方法中的一個參數,里面包含了用戶信息、請求信息等參數。

所以接下來我們看

?
1
this.getauthenticationmanager().authenticate(authrequest);

這里有一個authenticationmanager,但是真正調用的是providermanager

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class providermanager implements authenticationmanager, messagesourceaware, initializingbean {
  public authentication authenticate(authentication authentication) throws authenticationexception {
    class<? extends authentication> totest = authentication.getclass();
    authenticationexception lastexception = null;
    authentication result = null;
    boolean debug = logger.isdebugenabled();
    iterator var6 = this.getproviders().iterator();
 
    while(var6.hasnext()) {
      authenticationprovider provider = (authenticationprovider)var6.next();
      // 1.判斷是否有provider支持該authentication
      if (provider.supports(totest)) {
        // 2. 真正的邏輯判斷
        result = provider.authenticate(authentication);
      }
  }
}
  1. 這里首先通過provider判斷是否支持當前傳入進來的authentication,目前我們使用的是usernamepasswordauthenticationtoken,因為除了帳號密碼登錄的方式,還會有其他的方式,比如socialauthenticationtoken。
  2. 根據我們目前所使用的usernamepasswordauthenticationtoken,provider對應的是daoauthenticationprovider。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public authentication authenticate(authentication authentication) throws authenticationexception {
 
  userdetails user = this.usercache.getuserfromcache(username);
  if (user == null) {
    cachewasused = false;
    // 1.去獲取userdetails
    user = this.retrieveuser(username, (usernamepasswordauthenticationtoken)authentication);
  }
 
  try {
    // 2.用戶信息預檢查
    this.preauthenticationchecks.check(user);
    // 3.附加的檢查(密碼檢查)
    this.additionalauthenticationchecks(user, (usernamepasswordauthenticationtoken)authentication);
  } catch (authenticationexception var7) {   
  }
  // 4.最后的檢查
  this.postauthenticationchecks.check(user);
  // 5.返回真正的經過認證的authentication
  return this.createsuccessauthentication(principaltoreturn, authentication, user);
}
  1. 去調用自己實現的userdetailsservice,返回userdetails
  2. 對userdetails的信息進行校驗,主要是帳號是否被凍結,是否過期等
  3. 對密碼進行檢查,這里調用了passwordencoder
  4. 檢查userdetails是否可用。
  5. 返回經過認證的authentication

這里的兩次對userdetails的檢查,主要就是通過它的四個返回boolean類型的方法。
經過信息的校驗之后,通過usernamepasswordauthenticationtoken的構造方法,返回了一個經過認證的authentication。

拿到經過認證的authentication之后,會再去調用successhandler。或者未通過認證,去調用failurehandler。

認證結果如何在多個請求之間共享

再完成了用戶認證處理流程之后,我們思考一下是如何在多個請求之間共享這個認證結果的呢?

因為沒有做關于這方面的配置,所以可以聯想到默認的方式應該是在session中存入了認證結果。

那么是什么時候存放入session中的呢?

我們可以接著認證流程的源碼往后看,在通過attemptauthentication方法后,如果認證成功,會調用successfulauthentication,該方法中,不僅調用了successhandler,還有一行比較重要的代碼

?
1
securitycontextholder.getcontext().setauthentication(authresult);

securitycontextholder是對于threadlocal的封裝。 threadlocal是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,數據存儲以后,只有在指定線程中可以獲取到存儲的數據,對于其他線程來說則無法獲取到數據。 更多的關于threadlocal的原理可以看看我以前的文章。

一般來說同一個接口的請求和返回,都會是在一個線程中完成的。我們在securitycontextholder中放入了authresult,再其他地方也可以取出來的。

最后就是在securitycontextpersistencefilter中取出了authresult,并存入了session

securitycontextpersistencefilter也是一個過濾器,它處于整個security過濾器鏈的最前方,也就是說開始驗證的時候是最先通過該過濾器,驗證完成之后是最后通過。

獲取認證用戶信息

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * 獲取當前登錄的用戶
 * @return 完整的authentication
 */
@getmapping("/me1")
public object currentuser() {
  return securitycontextholder.getcontext().getauthentication();
}
 
@getmapping("/me2")
public object currentuser(authentication authentication) {
  return authentication;
}
 
/**
 * @param userdetails
 * @return 只包含了userdetails
 */
@getmapping("/me3")
public object cuurentuser(@authenticationprincipal userdetails userdetails) {
  return userdetails;
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/u013435893/article/details/79605239

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 插得爽| 二区三区不卡不卡视频 | 久久婷婷丁香五月色综合啪免费 | 亚洲日本中文字幕天天更新 | 日韩欧美一区二区在线 | 含羞草传媒网站免费进入欢迎 | 成人快插 | 精品国产人妻国语 | 好深快点再快点好爽视频 | 国产欧美精品专区一区二区 | 美女毛片视频 | 国产综合第一页 | 激情六月丁香婷婷四房播 | 黑人艹逼| 全彩调教侵犯h本子全彩妖气he | 校花小雪灌满了男人们的浓浆 | 精品国产免费久久久久久 | 亚洲2卡三卡4卡5卡精品 | 狠狠草视频 | 激情综合站 | 亚洲乱码一区二区三区国产精品 | 色天天综合色天天碰 | 欧美肥bb| 精品免费视频 | 激情综| 午夜小福利 | 98成人| 亚州性夜夜射在线观看 | 884aa草莓视频 | 乌克兰18sex性hd | 色多多在线视频 | 欧美亚洲国产一区二区三区 | 美女被草逼 | 欧美一级一级做性视频 | 亚欧美综合 | 9191免费永久观看 | 欧美精品久久久久久久免费观看 | 青青成人在线 | 韩国理论三级在线观看视频 | 成人午夜在线视频 | 国产日韩欧美成人 |