您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Spring Security如何優(yōu)雅的增加OAuth2協(xié)議授權模式,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
OAuth 2.0 是一個關于授權的開放的網(wǎng)絡協(xié)議,是目前最流行的授權機制。
數(shù)據(jù)的所有者告訴系統(tǒng),同意授權第三方應用進入系統(tǒng),獲取這些數(shù)據(jù)。系統(tǒng)從而產(chǎn)生一個短期的進入令牌(token),用來代替密碼,供第三方應用使用。
由于授權的場景眾多,OAuth 2.0 協(xié)議定義了獲取令牌的四種授權方式,分別是:
授權碼模式:授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式。它的特點就是通過客戶端的后臺服務器,與"服務提供商"的認證服務器進行互動。
簡化模式:簡化模式(implicit grant type)不通過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過了"授權碼"這個步驟,因此得名。所有步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不需要認證。
密碼模式:密碼模式(Resource Owner Password Credentials Grant)中,用戶向客戶端提供自己的用戶名和密碼??蛻舳耸褂眠@些信息,向"服務商提供商"索要授權。
客戶端模式:客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式并不屬于OAuth框架所要解決的問題。在這種模式中,用戶直接向客戶端注冊,客戶端以自己的名義要求"服務提供商"提供服務,其實不存在授權問題。
四種授權模式分別使用不同的
grant_type
來區(qū)分
雖然 OAuth3 協(xié)議定義了4種標準的授權模式,但是在實際開發(fā)過程中還是遠遠滿足不了各種變態(tài)的業(yè)務場景,需要我們?nèi)U展。
例如增加圖形驗證碼、手機驗證碼、手機號密碼登錄等等的場景
而常見的做法都是通過增加 過濾器Filter
的方式來擴展 Spring Security
授權,但是這樣的實現(xiàn)方式有兩個問題:
脫離了 OAuth3
的管理
不靈活:例如系統(tǒng)使用 密碼模式 授權,網(wǎng)頁版需要增加圖形驗證碼校驗,但是手機端APP又不需要的情況下,使用增加 Filter
的方式去實現(xiàn)就比較麻煩了。
所以目前在 Spring Security
中比較優(yōu)雅和靈活的擴展方式就是通過自定義 grant_type 來增加授權模式。
在擴展之前首先需要先了解 Spring Security
的整個授權流程,我以 密碼模式 為例去展開分析,如下圖所示
整個授權流程關鍵點分為以下兩個部分:
第一部分:關于授權類型 grant_type
的解析
每種 grant_type
都會有一個對應的 TokenGranter
實現(xiàn)類。
所有 TokenGranter
實現(xiàn)類都通過 CompositeTokenGranter
中的 tokenGranters
集合存起來。
然后通過判斷 grantType
參數(shù)來定位具體使用那個 TokenGranter
實現(xiàn)類來處理授權。
第二部分:關于授權登錄邏輯
每種 授權方式
都會有一個對應的 AuthenticationProvider
實現(xiàn)類來實現(xiàn)。
所有 AuthenticationProvider
實現(xiàn)類都通過 ProviderManager
中的 providers
集合存起來。
TokenGranter
類會 new 一個 AuthenticationToken
實現(xiàn)類,如 UsernamePasswordAuthenticationToken
傳給 ProviderManager
類。
而 ProviderManager
則通過 AuthenticationToken
來判斷具體使用那個 AuthenticationProvider
實現(xiàn)類來處理授權。
具體的登錄邏輯由 AuthenticationProvider
實現(xiàn)類來實現(xiàn),如 DaoAuthenticationProvider
。
根據(jù)上面的流程,擴展分為以下兩種場景
場景一:只對原有的授權邏輯進行增強或者擴展,如:用戶名密碼登錄前增加圖形驗證碼校驗。
該場景需要定義一個新的 grantType
類型,并新增對應的 TokenGranter
實現(xiàn)類 添加擴展內(nèi)容,然后加到 CompositeTokenGranter
中的 tokenGranters
集合里即可。
參考代碼:PwdImgCodeGranter.java
場景二:新加一種授權方式,如:手機號加密碼登錄。
該場景需要實現(xiàn)以下內(nèi)容:
定義一個新的 grantType
類型,并新增對應的 TokenGranter
實現(xiàn)類添加到 CompositeTokenGranter
中的 tokenGranters
集合里
新增一個 AuthenticationToken
實現(xiàn)類,用于存放該授權所需的信息。
新增一個 AuthenticationProvider
實現(xiàn)類 實現(xiàn)授權的邏輯,并重寫 supports
方法綁定步驟二的 AuthenticationToken
實現(xiàn)類
參考代碼:MobilePwdGranter.java
下面以 場景二 新增手機號加密碼授權方式為例,展示核心的代碼實現(xiàn)
創(chuàng)建 MobileAuthenticationToken
類,用于存儲手機號和密碼信息
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(); } }
創(chuàng)建 MobileAuthenticationProvider
類,實現(xiàn)登錄邏輯,并綁定 MobileAuthenticationToken
類
@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("手機號或密碼錯誤"); } if (!passwordEncoder.matches(password, user.getPassword())) { throw new BadCredentialsException("手機號或密碼錯誤"); } 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); } }
創(chuàng)建 MobilePwdGranter
類并定義 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, OAuth3RequestFactory requestFactory) { super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); this.authenticationManager = authenticationManager; } @Override protected OAuth3Authentication getOAuth3Authentication(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); } OAuth3Request storedOAuth3Request = getRequestFactory().createOAuth3Request(client, tokenRequest); return new OAuth3Authentication(storedOAuth3Request, userAuth); } }
// 添加手機號加密碼授權模式 tokenGranters.add(new MobilePwdGranter(authenticationManager, tokenServices, clientDetailsService, requestFactory));
使用以下地址,指定 grant_type
為 mobile_password
進行授權獲取 access_token
/oauth/token?grant_type=mobile_password&mobile={mobile}&password={password}
以上就是Spring Security如何優(yōu)雅的增加OAuth2協(xié)議授權模式,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學到更多知識。更多詳情敬請關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。