天天看點

【spring security學習筆記】身份驗證方式session-cookie、jwt、OAuth的學習session cookieJWTOAuth 2.0

  • session cookie
    • 使用Spring Session管理Session
    • session并發配置
    • 強制下線
  • JWT
    • jwt的組成
    • JWT工作流程
  • OAuth 2.0

session cookie

介紹:

Web應用開發大多是基于HTTP協定的。用戶端與服務端在使用HTTP協定進行互動時,協定本身并不會記錄用戶端的資訊或是狀态。這意味着HTTP協定是一個“無狀态”協定,而Web應用中的很多場景是需要儲存使用者狀态的。網站的安全性解決方案就需要對狀态進行驗證,通路一個受保護的資源的第一步便是檢查使用者是否通過登入驗證。這樣的情況催生了許多用于儲存使用者狀态的解決方案,Session-Cookie就是其中最為常見的一種。

Session-Cookie由Session與Cookie兩部分組成,分别存儲于服務端和用戶端。Session是一種用于記錄使用者的狀态資訊,被存儲于服務端的資料。例如目前使用者是否登入,身份與權限是怎樣的,這類資料大多會存儲于Session當中。 Cookie(或者被稱作HTTP Cookie)則是一小片被存儲在浏覽器的資料,往往在浏覽一個網站時便會産生。本身作用在于可以在通路網站的時候,記錄一些狀态資訊到用戶端。可以起到提升系統性能并且提高使用者體驗。在Session-Cookie體系中,Cookie主要用于記錄一串與Session關聯的辨別。該辨別往往被稱作“session-id”。 Session與Cookie不同的是,Cookie是一個真實存在的具體實作,而Session是一個相對抽象的概念,不同的語言與開發架構對Session有不同的實作方式。這兩者共同作用,使得使用者即便是在使用“無狀态”協定與服務端互動,依舊能在不同頁面共享一些資訊。流程如下:

· 客戶發送請求到服務端。

· 服務端收到請求之後便會在内部建立Session,之後傳回響應。在響應頭中,包含Set-Cookie資訊,其中内容就包含Session-id。

· 當用戶端收到包含Set-Cookie的響應之後,後續的所有請求就會帶上Cookie。

· 服務端可以根據Cookie中的Session-id讓每個請求與Session逐一對應,實作請求間的狀态共享。

使用Spring Session管理Session

在Spring Boot開發中,Session-Cookie預設由Web容器(例如Tomcat)維護。例如,通路一個Web容器是Tomcat的Spring Boot應用,預設傳回的響應頭中會設定一條鍵為JSESSIONID的Cookie

Session預設情況下是儲存于服務端的JVM記憶體當中。在該條件下當服務端程式重新開機時,Session将會丢失。這也意味着使用者會集體掉線,如果要繼續操作則需要重新登入。在某些場景下,該情況會嚴重影響使用者的使用體驗。這不得不将Session的管理從JVM記憶體中剝離出來。 Spring Session便提供了一套方案用于解決Session管理的問題,使其不依賴于特定的應用程式容器實作Session叢集化。下面将講解Spring Boot整合Spring Session的步驟。

(1)更新依賴

整合Spring Session的第一個步驟是更新依賴。Spring Session可選的容器類型有四種,分别是Redis、MongoDB、JDBC和HAZELCAST。選擇好對應的容器類型後,再根據類型選擇對應的依賴項。比如選擇Redis作為Session的外部容器,則需要引入spring-session-data-redis。

(2)修改配置

在application.properties中:

spring:

session:

store-type: redis

得益于Spring Boot的自動配置,加上該配置項之後等同于使用了注解@EnableRedisHttpSession。這将建立名為springSessionRepositoryFilter的過濾器。該過濾器負責将容器中的HttpSession替換為Spring Session。

(3)配置Redis連接配接

redis:

#redis域名

hostname: localhost

#redis端口

port: 6379

#redis密碼

password: NlzWZLvvCF5Gzzby

(4)檢驗結果 啟動程式,并且成功登入之後,可以通過Redis的GUI管理工具檢視對應命名空間下的存儲情況

修改SecurityConfig.java

session并發配置

Spring Security中預設對session的并發數并沒有限制。換句話說,一個使用者的賬号和密碼在預設條件下可以供任意數量的用戶端登入。這種情況在某些場景下是難以接受的,例如,一些付費的視訊,對于同賬戶的用戶端線上數量會進行限制。Spring Security對于這樣的場景也提供了支援。

首先定義一個SessionInformationExpiredStrategy的實作作為失效政策,用于傳回異常資訊。ParallelismSessionExpiredStrategy.java:

@Configuration

public class Parallelismsessionexpiredstrategy implements
SessioninformationexpiredStrategy {
private final ObjectMapper objectMapper;
public void onExpiredSessionDetected(Sessioninformationexpiredevent event)throws Ioexception, Servletexception{
//傳回異常資訊
event. getresponse(). setContentType("application/ison; charset=utf-8");
event. getresponse().getwriter(). write(objectMapper. writevalueasstring(R.failed("達到并發上限")));
}
}



           

SecurityConfig中加上sessionManagement配置,SecurityConfig.java:

@Configuration
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true,secureEnabled = true,jsr250Enabled = true)
public class Securityconfig extends WebSecurityConfigurerAdapter {
@override
protectedvoidconfigure(httpsecurityhttp)throws Exception{
http
//…
.sessionmanagement()//并發 Session上限為1
.maximumsessions(1)//達到上限後是否阻止登入
.maxSessionsPreventslogin( true)
//失效 Session政策
.expiredSessionStrategy(new
ParallelismSessionExpiredstrategy(mapper));//,' 
           

其中,maxSessionsPreventsLogin用于控制達到Session并發上限後的政策,True代表将阻止後續的登入操作,False代表将會使之前登入的Session強制失效。另外,失效Session的請求結果将按照expiredSessionStrategy中配置的政策進行傳回。

強制下線

Session-Cookie的特點在于服務端可以監聽并控制使用者的會話狀态。這為使用管理模組的開發提供了很大便利。會話管理中強制下線會是一個常見需求,如果一個Web應用中出現違規操作,可以使用強制下線功能為系統提供保護。

@Component
@RequiredArgsConstructor
public class SessionUtils{
private final SessionRegistry sessionRegistry;
public void expireUserSessions(String username){
for (Object principal:sessionRegistry. getAllPrincipals()){
if (principal instanceof SecurityProperties. User){
UserDetails userDetails =(UserDetails) principal;
//周遊 sessionRegistry中的 principal找到對應使用者的 Session
if (userDetails. getUsername () equals (username)){
for (SessionInformation information:
sessionRegistry. getAllSessions (userDetails, true)){
//讓 session立刻失效
information.expireNow(); 
}
}
}
}

           

需要某個使用者強制下線時調用 SessionUtils的expireUserSessions()指令即可。

JWT

基于Session-Cookie模式的身份驗證,這類模式的特點在于後端會維護使用者的狀态。在常見身份驗證方式中,有一種方式與Session-Cookie有着鮮明差異,它不用于後端維護使用者狀态,這一方式正是将介紹的對象——JWT。

JWT是一個開放标準(RFC 7519),它定義了一種緊湊且自包含的方式,用于在各端之間将安全資訊以JSON對象的形式進行傳遞。由于此資訊是經過數字簽名的,是以可以被驗證和信任。另外,還可以使用HMAC或者RSA算法對JWT進行加密。

jwt的組成

JWT以緊湊的三部分組成,各部分以(.)分隔,形如xxxx.yyy.zzz。這三部分分别是:

· Header(标頭)。通常由兩部分組成,令牌的類型(即JWT)和所使用的簽名算法,例如HMAC SHA256或RSA。

· Payload(負載)。負載中包含不同類型的聲明(Claims)。有已注冊聲明(預定義聲明,包含簽發人、逾時時間等資訊)、公有聲明和私有聲明(由簽發者用于在各端傳遞安全資訊的聲明,可随意定義)。

· Signature(簽名)。基于标頭中定義的加密算法進行加密的簽名。例如,加密算法為HMACSHA256的話,簽名過程将會是: 簽名的作用在于保證消息在傳輸過程中是未被更改的,并且如果使用私鑰進行簽名,還可以對發送者身份進行進一步的認證。

基于JWT加密并且可攜帶安全資訊的特點,後端可以将原本儲存于Session中的資訊儲存至JWT的私有聲明,然後要求用戶端在每次請求中都攜帶JWT。 以這種方式實作後端服務的無狀态化。

JWT帶來後端無狀态化的同時,也帶來了不少好處:

(1)跨域與CORS 傳統的認證方式中,Cookies是預設隻能用于單個域名和子域名間進行消息傳遞。如果碰到域名不同的情況(也就是跨域),整個處理過程會變得繁瑣。JWT不依賴Cookie,大多以Authorization:Bearer {JWT}這樣的格式作為請求頭進行傳遞,不會被跨域請求所影響。

(2)跨平台解決方案 同樣是受限于Cookies的特性,移動平台與Cookies并不能很好地融合,存在諸多限制。JWT相比Cookie-Session更适合作為跨平台的認證解決方案。

(3)友善擴充,提升後端性能 Session-Cookie的驗證過程中基本都需要對存儲子產品進行通路,特别在于分布式架構中的認證過程,後端服務需要對外部存儲進行通路,其中必然存在資料傳輸帶來的時間損耗。JWT的驗證過程中僅需要根據加密算法對JWT進行驗簽解密。相對來說,不會有擴充和性能方面的困擾。

JWT工作流程

通常情況下JWT通過通路一個用于登入的URL來擷取。登入成功後,用戶端将會在之後的請求的每個請求體中,以Authorization: Bearer {JWT}的格式将JWT設定為請求頭。服務端将會對JWT内容進行驗簽解密,并做出相應的響應。

OAuth 2.0

第三方應用授權在網際網路服務中被廣泛地運用。在這一功能的背後,大多會使用到OAuth這一授權技術。OAuth是一個用于授權的網絡标準,目前主流的版本為2.0版.

使用OAuth 2.0這一授權标準,可以讓第三方應用程式擷取使用者在某一網絡服務(例如QQ、GitHub)上有限的賬戶通路權限。比如,使用QQ的第三方授權可以擷取使用者的QQ昵稱頭像等資訊。實作方式是通過将身份驗證這一環委托給承載使用者賬戶的伺服器(通常被稱作認證伺服器,Authorization Server),并授權第三方應用(通常被稱作資源伺服器,Resource Server)通路使用者賬戶。

OAuth 2.0中涉及四個角色之間的資訊交換,分别是: ·

 使用者:使用者擁有授權/資源伺服器上的賬戶,在流程中授予用戶端通路賬戶的權限。 ·

 授權伺服器:負責驗證使用者身份,向第三方應用頒發令牌。 · 資源伺服器:負責保管使用者賬戶。

· 第三方應用(用戶端):想要通路使用者賬戶的應用程式。

OAuth 2.0提供四種不同的授權模式以适應各種應用場景: · 授權碼模式 · 密碼模式 · 簡化模式 用戶端模式

繼續閱讀