欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Security獲取用戶認(rèn)證信息的實(shí)現(xiàn)流程

 更新時(shí)間:2022年12月27日 15:20:02   作者:一個(gè)雙子座的Java攻城獅  
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框架。它提供了一組可以在Spring應(yīng)用上下文中配置的Bean,充分利用了Spring IoC,DI和AOP功能,為應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制功能

登錄用戶數(shù)據(jù)獲取

SecurityContextHolder

? Spring Security 會(huì)將登錄用戶數(shù)據(jù)保存在 Session 中。但是,為了使用方便,Spring Security在此基礎(chǔ)上還做了一些改進(jìn),其中最主要的一個(gè)變化就是線程綁定。當(dāng)用戶登錄成功后,Spring Security 會(huì)將登錄成功的用戶信息保存到 SecurityContextHolder 中。

? SecurityContextHolder 中的數(shù)據(jù)保存默認(rèn)是通過(guò)ThreadLocal 來(lái)實(shí)現(xiàn)的,使用 ThreadLocal 創(chuàng)建的變量只能被當(dāng)前線程訪問(wèn),不能被其他線程訪問(wèn)和修改,也就是用戶數(shù)據(jù)和請(qǐng)求線程綁定在一起。當(dāng)?shù)卿浾?qǐng)求處理完畢后,Spring Security 會(huì)將 SecurityContextHolder 中的數(shù)據(jù)拿出來(lái)保存到 Session 中,同時(shí)將 SecurityContexHolder 中的數(shù)據(jù)清空。以后每當(dāng)有請(qǐng)求到來(lái)時(shí),Spring Security 就會(huì)先從 Session 中取出用戶登錄數(shù)據(jù),保存到SecurityContextHolder 中,方便在該請(qǐng)求的后續(xù)處理過(guò)程中使用,同時(shí)在請(qǐng)求結(jié)束時(shí)將 SecurityContextHolder 中的數(shù)據(jù)拿出來(lái)保存到 Session 中,然后將SecurityContextHolder 中的數(shù)據(jù)清空。

? 實(shí)際上 SecurityContextHolder 中存儲(chǔ)是 SecurityContext,在 SecurityContext 中存儲(chǔ)是 Authentication。

這種設(shè)計(jì)是典型的策略設(shè)計(jì)模式:

public class SecurityContextHolder {
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
	public static final String MODE_GLOBAL = "MODE_GLOBAL";
	private static final String MODE_PRE_INITIALIZED = "MODE_PRE_INITIALIZED";
	private static SecurityContextHolderStrategy strategy;
  //....
	private static void initializeStrategy() {
		if (MODE_PRE_INITIALIZED.equals(strategyName)) {
			Assert.state(strategy != null, "When using " + MODE_PRE_INITIALIZED
					+ ", setContextHolderStrategy must be called with the fully constructed strategy");
			return;
		}
		if (!StringUtils.hasText(strategyName)) {
			// Set default
			strategyName = MODE_THREADLOCAL;
		}
		if (strategyName.equals(MODE_THREADLOCAL)) {
			strategy = new ThreadLocalSecurityContextHolderStrategy();
			return;
		}
		if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
			return;
		}
		if (strategyName.equals(MODE_GLOBAL)) {
			strategy = new GlobalSecurityContextHolderStrategy();
			return;
		}
    //.....
  }
}
  • MODE THREADLOCAL:這種存放策略是將 SecurityContext 存放在 ThreadLocal中,大家知道 Threadlocal 的特點(diǎn)是在哪個(gè)線程中存儲(chǔ)就要在哪個(gè)線程中讀取,這其實(shí)非常適合 web 應(yīng)用,因?yàn)樵谀J(rèn)情況下,一個(gè)請(qǐng)求無(wú)論經(jīng)過(guò)多少 Filter 到達(dá) Servlet,都是由一個(gè)線程來(lái)處理的。這也是 SecurityContextHolder 的默認(rèn)存儲(chǔ)策略,這種存儲(chǔ)策略意味著如果在具體的業(yè)務(wù)處理代碼中,開啟了子線程,在子線程中去獲取登錄用戶數(shù)據(jù),就會(huì)獲取不到。
  • MODE INHERITABLETHREADLOCAL:這種存儲(chǔ)模式適用于多線程環(huán)境,如果希望在子線程中也能夠獲取到登錄用戶數(shù)據(jù),那么可以使用這種存儲(chǔ)模式。
  • MODE GLOBAL:這種存儲(chǔ)模式實(shí)際上是將數(shù)據(jù)保存在一個(gè)靜態(tài)變量中,在 JavaWeb開發(fā)中,這種模式很少使用到。

SecurityContextHolderStrategy

通過(guò) SecurityContextHolder 可以得知,SecurityContextHolderStrategy 接口用來(lái)定義存儲(chǔ)策略方法

public interface SecurityContextHolderStrategy {
	void clearContext();
	SecurityContext getContext();
	void setContext(SecurityContext context);
	SecurityContext createEmptyContext();
}

接口中一共定義了四個(gè)方法:

  • clearContext:該方法用來(lái)清除存儲(chǔ)的 SecurityContext對(duì)象。
  • getContext:該方法用來(lái)獲取存儲(chǔ)的 SecurityContext 對(duì)象。
  • setContext:該方法用來(lái)設(shè)置存儲(chǔ)的 SecurityContext 對(duì)象。
  • create Empty Context:該方法則用來(lái)創(chuàng)建一個(gè)空的 SecurityContext 對(duì)象。

代碼中獲取認(rèn)證之后用戶數(shù)據(jù)

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
      Authentication authentication = SecurityContextHolder
        .getContext().getAuthentication();
      User principal = (User) authentication.getPrincipal();
      System.out.println("身份 :"+principal.getUsername());
      System.out.println("憑證 :"+authentication.getCredentials());
      System.out.println("權(quán)限 :"+authentication.getAuthorities());
      return "hello security";
    }
}

多線程情況下獲取用戶數(shù)據(jù)

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
      new Thread(()->{
        Authentication authentication = SecurityContextHolder
          .getContext().getAuthentication();
        User principal = (User) authentication.getPrincipal();
        System.out.println("身份 :"+principal.getUsername());
        System.out.println("憑證 :"+authentication.getCredentials());
        System.out.println("權(quán)限 :"+authentication.getAuthorities());
      }).start();
      return "hello security";
    }
}

可以看到默認(rèn)策略,是無(wú)法在子線程中獲取用戶信息,如果需要在子線程中獲取必須使用第二種策略,默認(rèn)策略是通過(guò) System.getProperty 加載的,因此我們可以通過(guò)增加 VM Options 參數(shù)進(jìn)行修改。

-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL

頁(yè)面上獲取用戶信息

引入依賴

<dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-springsecurity5</artifactId>
  <version>3.0.4.RELEASE</version>
</dependency>

頁(yè)面加入命名空間

<html lang="en" xmlns:th="https://www.thymeleaf.org" 
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

頁(yè)面中使用

<!--獲取認(rèn)證用戶名-->
<ul>
  <li sec:authentication="principal.username"></li>
  <li sec:authentication="principal.authorities"></li>
  <li sec:authentication="principal.accountNonExpired"></li>
  <li sec:authentication="principal.accountNonLocked"></li>
  <li sec:authentication="principal.credentialsNonExpired"></li>
</ul>

到此這篇關(guān)于Spring Security獲取用戶認(rèn)證信息的實(shí)現(xiàn)流程的文章就介紹到這了,更多相關(guān)Spring Security獲取認(rèn)證信息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論