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

Spring Security如何優(yōu)雅的增加OAuth2協(xié)議授權(quán)模式

 更新時(shí)間:2020年09月04日 10:01:07   作者:zlt2000  
這篇文章主要介紹了Spring Security如何優(yōu)雅的增加OAuth2協(xié)議授權(quán)模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、什么是OAuth2協(xié)議?

OAuth 2.0 是一個(gè)關(guān)于授權(quán)的開(kāi)放的網(wǎng)絡(luò)協(xié)議,是目前最流行的授權(quán)機(jī)制。

數(shù)據(jù)的所有者告訴系統(tǒng),同意授權(quán)第三方應(yīng)用進(jìn)入系統(tǒng),獲取這些數(shù)據(jù)。系統(tǒng)從而產(chǎn)生一個(gè)短期的進(jìn)入令牌(token),用來(lái)代替密碼,供第三方應(yīng)用使用。

由于授權(quán)的場(chǎng)景眾多,OAuth 2.0 協(xié)議定義了獲取令牌的四種授權(quán)方式,分別是:

  • 授權(quán)碼模式:授權(quán)碼模式(authorization code)是功能最完整、流程最嚴(yán)密的授權(quán)模式。它的特點(diǎn)就是通過(guò)客戶端的后臺(tái)服務(wù)器,與"服務(wù)提供商"的認(rèn)證服務(wù)器進(jìn)行互動(dòng)。
  • 簡(jiǎn)化模式:簡(jiǎn)化模式(implicit grant type)不通過(guò)第三方應(yīng)用程序的服務(wù)器,直接在瀏覽器中向認(rèn)證服務(wù)器申請(qǐng)令牌,跳過(guò)了"授權(quán)碼"這個(gè)步驟,因此得名。所有步驟在瀏覽器中完成,令牌對(duì)訪問(wèn)者是可見(jiàn)的,且客戶端不需要認(rèn)證。
  • 密碼模式:密碼模式(Resource Owner Password Credentials Grant)中,用戶向客戶端提供自己的用戶名和密碼??蛻舳耸褂眠@些信息,向"服務(wù)商提供商"索要授權(quán)。
  • 客戶端模式:客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向"服務(wù)提供商"進(jìn)行認(rèn)證。嚴(yán)格地說(shuō),客戶端模式并不屬于OAuth框架所要解決的問(wèn)題。在這種模式中,用戶直接向客戶端注冊(cè),客戶端以自己的名義要求"服務(wù)提供商"提供服務(wù),其實(shí)不存在授權(quán)問(wèn)題。

四種授權(quán)模式分別使用不同的 grant_type 來(lái)區(qū)分

二、為什么要自定義授權(quán)類(lèi)型?

雖然 OAuth2 協(xié)議定義了4種標(biāo)準(zhǔn)的授權(quán)模式,但是在實(shí)際開(kāi)發(fā)過(guò)程中還是遠(yuǎn)遠(yuǎn)滿足不了各種變態(tài)的業(yè)務(wù)場(chǎng)景,需要我們?nèi)U(kuò)展。

例如增加圖形驗(yàn)證碼、手機(jī)驗(yàn)證碼、手機(jī)號(hào)密碼登錄等等的場(chǎng)景

而常見(jiàn)的做法都是通過(guò)增加 過(guò)濾器Filter 的方式來(lái)擴(kuò)展 Spring Security 授權(quán),但是這樣的實(shí)現(xiàn)方式有兩個(gè)問(wèn)題:

  • 脫離了 OAuth2 的管理
  • 不靈活:例如系統(tǒng)使用 密碼模式 授權(quán),網(wǎng)頁(yè)版需要增加圖形驗(yàn)證碼校驗(yàn),但是手機(jī)端APP又不需要的情況下,使用增加 Filter 的方式去實(shí)現(xiàn)就比較麻煩了。

所以目前在 Spring Security 中比較優(yōu)雅和靈活的擴(kuò)展方式就是通過(guò)自定義 grant_type 來(lái)增加授權(quán)模式。

三、實(shí)現(xiàn)思路

在擴(kuò)展之前首先需要先了解 Spring Security 的整個(gè)授權(quán)流程,我以 密碼模式 為例去展開(kāi)分析,如下圖所示

3.1. 流程分析

整個(gè)授權(quán)流程關(guān)鍵點(diǎn)分為以下兩個(gè)部分:

第一部分:關(guān)于授權(quán)類(lèi)型 grant_type 的解析

  • 每種 grant_type 都會(huì)有一個(gè)對(duì)應(yīng)的 TokenGranter 實(shí)現(xiàn)類(lèi)。
  • 所有 TokenGranter 實(shí)現(xiàn)類(lèi)都通過(guò) CompositeTokenGranter 中的 tokenGranters 集合存起來(lái)。
  • 然后通過(guò)判斷 grantType 參數(shù)來(lái)定位具體使用那個(gè) TokenGranter 實(shí)現(xiàn)類(lèi)來(lái)處理授權(quán)。

 第二部分:關(guān)于授權(quán)登錄邏輯

  • 每種 授權(quán)方式 都會(huì)有一個(gè)對(duì)應(yīng)的 AuthenticationProvider 實(shí)現(xiàn)類(lèi)來(lái)實(shí)現(xiàn)。
  • 所有 AuthenticationProvider 實(shí)現(xiàn)類(lèi)都通過(guò) ProviderManager 中的 providers 集合存起來(lái)。
  • TokenGranter 類(lèi)會(huì) new 一個(gè) AuthenticationToken 實(shí)現(xiàn)類(lèi),如 UsernamePasswordAuthenticationToken 傳給 ProviderManager 類(lèi)。
  • ProviderManager 則通過(guò) AuthenticationToken 來(lái)判斷具體使用那個(gè) AuthenticationProvider 實(shí)現(xiàn)類(lèi)來(lái)處理授權(quán)。

具體的登錄邏輯由 AuthenticationProvider 實(shí)現(xiàn)類(lèi)來(lái)實(shí)現(xiàn),如 DaoAuthenticationProvider

 3.2. 擴(kuò)展分析

根據(jù)上面的流程,擴(kuò)展分為以下兩種場(chǎng)景

場(chǎng)景一:只對(duì)原有的授權(quán)邏輯進(jìn)行增強(qiáng)或者擴(kuò)展,如:用戶名密碼登錄前增加圖形驗(yàn)證碼校驗(yàn)。

該場(chǎng)景需要定義一個(gè)新的 grantType 類(lèi)型,并新增對(duì)應(yīng)的 TokenGranter 實(shí)現(xiàn)類(lèi) 添加擴(kuò)展內(nèi)容,然后加到 CompositeTokenGranter 中的 tokenGranters 集合里即可。

參考代碼:PwdImgCodeGranter.java

場(chǎng)景二:新加一種授權(quán)方式,如:手機(jī)號(hào)加密碼登錄。

該場(chǎng)景需要實(shí)現(xiàn)以下內(nèi)容:

  • 定義一個(gè)新的 grantType 類(lèi)型,并新增對(duì)應(yīng)的 TokenGranter 實(shí)現(xiàn)類(lèi)添加到 CompositeTokenGranter 中的 tokenGranters 集合里
  • 新增一個(gè) AuthenticationToken 實(shí)現(xiàn)類(lèi),用于存放該授權(quán)所需的信息。
  • 新增一個(gè) AuthenticationProvider 實(shí)現(xiàn)類(lèi) 實(shí)現(xiàn)授權(quán)的邏輯,并重寫(xiě) supports 方法綁定步驟二的 AuthenticationToken 實(shí)現(xiàn)類(lèi)

參考代碼:MobilePwdGranter.java

 四、代碼實(shí)現(xiàn)

下面以 場(chǎng)景二 新增手機(jī)號(hào)加密碼授權(quán)方式為例,展示核心的代碼實(shí)現(xiàn)

4.1. 創(chuàng)建 AuthenticationToken 實(shí)現(xiàn)類(lèi)

創(chuàng)建 MobileAuthenticationToken 類(lèi),用于存儲(chǔ)手機(jī)號(hào)和密碼信息

public class MobileAuthenticationToken extends AbstractAuthenticationToken {
	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

	private final Object principal;
	private Object credentials;

	public MobileAuthenticationToken(String mobile, String password) {
		super(null);
		this.principal = mobile;
		this.credentials = password;
		setAuthenticated(false);
	}

	public MobileAuthenticationToken(Object principal, Object credentials,
									 Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.principal = principal;
		this.credentials = credentials;
		super.setAuthenticated(true);
	}

	@Override
	public Object getCredentials() {
		return this.credentials;
	}

	@Override
	public Object getPrincipal() {
		return this.principal;
	}

	@Override
	public void setAuthenticated(boolean isAuthenticated) {
		if (isAuthenticated) {
			throw new IllegalArgumentException(
					"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
		}
		super.setAuthenticated(false);
	}

	@Override
	public void eraseCredentials() {
		super.eraseCredentials();
	}
}

4.2. 創(chuàng)建 AuthenticationProvider 實(shí)現(xiàn)類(lèi)

創(chuàng)建 MobileAuthenticationProvider 類(lèi),實(shí)現(xiàn)登錄邏輯,并綁定 MobileAuthenticationToken 類(lèi)

@Setter
public class MobileAuthenticationProvider implements AuthenticationProvider {
  private ZltUserDetailsService userDetailsService;
  private PasswordEncoder passwordEncoder;

  @Override
  public Authentication authenticate(Authentication authentication) {
    MobileAuthenticationToken authenticationToken = (MobileAuthenticationToken) authentication;
    String mobile = (String) authenticationToken.getPrincipal();
    String password = (String) authenticationToken.getCredentials();
    UserDetails user = userDetailsService.loadUserByMobile(mobile);
    if (user == null) {
      throw new InternalAuthenticationServiceException("手機(jī)號(hào)或密碼錯(cuò)誤");
    }
    if (!passwordEncoder.matches(password, user.getPassword())) {
      throw new BadCredentialsException("手機(jī)號(hào)或密碼錯(cuò)誤");
    }
    MobileAuthenticationToken authenticationResult = new MobileAuthenticationToken(user, password, user.getAuthorities());
    authenticationResult.setDetails(authenticationToken.getDetails());
    return authenticationResult;
  }

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

4.3. 創(chuàng)建 TokenGranter 實(shí)現(xiàn)類(lèi)

創(chuàng)建 MobilePwdGranter 類(lèi)并定義 grant_type 的值為 mobile_password

public class MobilePwdGranter extends AbstractTokenGranter {
  private static final String GRANT_TYPE = "mobile_password";

  private final AuthenticationManager authenticationManager;

  public MobilePwdGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices
      , ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
    super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
    this.authenticationManager = authenticationManager;
  }

  @Override
  protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
    Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
    String mobile = parameters.get("mobile");
    String password = parameters.get("password");
    parameters.remove("password");

    Authentication userAuth = new MobileAuthenticationToken(mobile, password);
    ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
    userAuth = authenticationManager.authenticate(userAuth);
    if (userAuth == null || !userAuth.isAuthenticated()) {
      throw new InvalidGrantException("Could not authenticate mobile: " + mobile);
    }

    OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
    return new OAuth2Authentication(storedOAuth2Request, userAuth);
  }
}

4.4. 加到 CompositeTokenGranter 中的集合里

// 添加手機(jī)號(hào)加密碼授權(quán)模式
tokenGranters.add(new MobilePwdGranter(authenticationManager, tokenServices, clientDetailsService, requestFactory));

4.5. 測(cè)試

使用以下地址,指定 grant_typemobile_password 進(jìn)行授權(quán)獲取 access_token

/oauth/token?grant_type=mobile_password&mobile={mobile}&password={password}

五、參考樣例

詳細(xì)的代碼實(shí)現(xiàn)可以參考

https://gitee.com/zlt2000/microservices-platform/tree/master/zlt-uaa

到此這篇關(guān)于Spring Security如何優(yōu)雅的增加OAuth2協(xié)議授權(quán)模式的文章就介紹到這了,更多相關(guān)Spring Security OAuth2內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java HashMap算法原理詳細(xì)講解

    Java HashMap算法原理詳細(xì)講解

    在java開(kāi)發(fā)中,HashMap是最常用、最常見(jiàn)的集合容器類(lèi)之一,文中通過(guò)示例代碼介紹HashMap為啥要二次Hash,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02
  • springMVC中@RequestParam和@RequestPart的區(qū)別

    springMVC中@RequestParam和@RequestPart的區(qū)別

    本文主要介紹了springMVC中@RequestParam和@RequestPart的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • JavaWeb?使用DBUtils實(shí)現(xiàn)增刪改查方式

    JavaWeb?使用DBUtils實(shí)現(xiàn)增刪改查方式

    這篇文章主要介紹了JavaWeb?使用DBUtils實(shí)現(xiàn)增刪改查方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 使用Spring Security控制會(huì)話的方法

    使用Spring Security控制會(huì)話的方法

    在本文中,我們將說(shuō)明Spring Security如何允許我們控制HTTP會(huì)話。這篇文章主要介紹了使用Spring Security控制會(huì)話 ,需要的朋友可以參考下
    2019-05-05
  • Java生成Jar包方法步驟

    Java生成Jar包方法步驟

    在Java開(kāi)發(fā)中,打包成JAR文件是一種常見(jiàn)的方式,本文主要介紹了Java生成Jar包方法步驟,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • Java計(jì)算兩個(gè)程序運(yùn)行時(shí)間的實(shí)例

    Java計(jì)算兩個(gè)程序運(yùn)行時(shí)間的實(shí)例

    下面小編就為大家?guī)?lái)一篇Java計(jì)算兩個(gè)程序運(yùn)行時(shí)間的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • 深入淺出講解Java比較器及數(shù)學(xué)常用類(lèi)

    深入淺出講解Java比較器及數(shù)學(xué)常用類(lèi)

    這篇文章主要介紹了深入淺出講解Java比較器及數(shù)學(xué)常用類(lèi),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Java Hutool 包工具類(lèi)推薦 ExcelUtil詳解

    Java Hutool 包工具類(lèi)推薦 ExcelUtil詳解

    這篇文章主要介紹了Java Hutool 包工具類(lèi)推薦 ExcelUtil詳解,需要引入hutool包,版本號(hào)可根據(jù)實(shí)際情況更換,除hutool包之外,還需要引入操作Excel必要包,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 總結(jié)Java常用加解密方法AES?SHA1?md5

    總結(jié)Java常用加解密方法AES?SHA1?md5

    這篇文章主要為大家介紹了Java常用加密方法AES?SHA1?md5總結(jié)及示例demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • SpringBoot調(diào)用第三方WebService接口的兩種方法

    SpringBoot調(diào)用第三方WebService接口的兩種方法

    本文主要介紹了SpringBoot調(diào)用第三方WebService接口的兩種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評(píng)論