javascript
带有JWT示例的Spring Oauth2
有時以前,我們發(fā)表了一篇文章,分享了一種在云環(huán)境中實現無狀態(tài)會話的自定義方法。 今天,讓我們探討為Spring Boot應用程序設置Oauth2身份驗證的另一個流行用例。 在此示例中,我們將使用JSON Web令牌(JWT)作為Oauth2令牌的格式。
該示例部分是基于Spring Security Oauth 2的官方示例開發(fā)的。但是,我們將專注于理解Oauth 2請求的原理。
源代碼位于https://github.com/tuanngda/spring-boot-oauth2-demo.git
背景
Oauth2和JWT
當您要使用Oauth2和JWT時,我們將不做詳細介紹。 通常,如果需要允許其他人為您的服務構建前端應用程序,則可能需要采用Oauth。 我們專注于Oauth2和JWT,因為它們是市場上最流行的身份驗證框架和協(xié)議。
Spring安全Oauth 2
Spring Security Oauth2是Oauth 2的實現,它是在Spring Security之上構建的,Spring Security是一個非常可擴展的身份驗證框架。
總體而言,Spring Security包括2個基本步驟:為每個請求創(chuàng)建一個身份驗證對象,并根據身份驗證應用授權檢查。 第一步是在多層安全篩選器中完成的。 根據配置,每一層都可以幫助創(chuàng)建基本身份驗證,摘要身份驗證,表單身份驗證或我們選擇自行實現的任何自定義身份驗證的身份驗證。 我們在上一篇文章中構建的客戶端會話是一種自定義身份驗證,而Spring Security Oauth 2是另一種自定義身份驗證。
因為在此示例中,我們的應用程序既提供令牌又使用令牌,因此Spring Security Oauth 2不應是應用程序的唯一身份驗證層。 我們需要另一種身份驗證機制來保護令牌提供者端點。
對于集群環(huán)境,令牌或簽名令牌的秘密(對于JWT)假定是持久的,但是我們跳過此步驟以簡化示例。 同樣,用戶身份驗證和客戶端身份都是硬編碼的。
系統(tǒng)設計
總覽
在我們的應用程序中,我們需要設置3個組件
- 授權端點和令牌端點,以幫助提供Oauth 2令牌。
- WebSecurityConfigurerAdapter,這是一個身份驗證層,其硬編碼順序為3(根據Dave Syer )。 該身份驗證層將為包含Oauth 2令牌的任何請求設置身份驗證和委托人。
- 如果令牌丟失,則另一種身份驗證機制可以保護令牌端點和其他資源。 在此示例中,我們選擇基本身份驗證是為了簡化編寫測試時的操作。 由于我們未指定順序,因此它將采用默認值100。對于Spring安全性,順序越低,優(yōu)先級越高; 因此,我們應該期望Oauth 2在FilterChainProxy中進行基本身份驗證之前。 在IDE中檢查證明我們的設置正確。
在上圖中,Oauth2AuthenticationProcessingFilter出現在BasicAuthenticationFilter的前面。
授權服務器配置
這是我們的授權和令牌端點配置
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {@Value("${resource.id:spring-boot-application}")private String resourceId;@Value("${access_token.validity_period:3600}")int accessTokenValiditySeconds = 3600;@Autowiredprivate AuthenticationManager authenticationManager;@Beanpublic JwtAccessTokenConverter accessTokenConverter() {return new JwtAccessTokenConverter();}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(this.authenticationManager).accessTokenConverter(accessTokenConverter());}@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("normal-app").authorizedGrantTypes("authorization_code", "implicit").authorities("ROLE_CLIENT").scopes("read", "write").resourceIds(resourceId).accessTokenValiditySeconds(accessTokenValiditySeconds).and().withClient("trusted-app").authorizedGrantTypes("client_credentials", "password").authorities("ROLE_TRUSTED_CLIENT").scopes("read", "write").resourceIds(resourceId).accessTokenValiditySeconds(accessTokenValiditySeconds).secret("secret");} }關于此實現,沒有什么值得注意的事情。
- 設置JWT令牌就像使用JwtAccessTokenConverter一樣簡單。 因為我們從未設置簽名密鑰,所以它是隨機生成的。 如果我們打算將應用程序部署到云中,則必須在所有授權服務器之間同步簽名密鑰。
- 除了選擇創(chuàng)建身份驗證管理器之外,我們還選擇從Spring容器中注入現有的身份驗證管理器。 通過此步驟,我們可以與基本身份驗證過濾器共享身份驗證管理器。
- 可能有受信任的應用程序,而不是受信任的應用程序。 受信任的應用程序可以有自己的秘密。 這是客戶憑證授權授予所必需的。 除客戶端憑據外,所有其他三個授予都需要資源所有者的憑據。
- 我們允許匿名檢查令牌端點。 使用此配置,無需基本身份驗證或Oauth 2令牌即可訪問檢查令牌。
資源服務器配置
這是我們的資源服務器配置配置
@Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {@Value("${resource.id:spring-boot-application}")private String resourceId;@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(resourceId);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.requestMatcher(new OAuthRequestedMatcher()).authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();}private static class OAuthRequestedMatcher implements RequestMatcher {public boolean matches(HttpServletRequest request) {String auth = request.getHeader("Authorization");// Determine if the client request contained an OAuth Authorizationboolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");boolean haveAccessToken = request.getParameter("access_token")!=null;return haveOauth2Token || haveAccessToken;}}}這里有幾件事要注意:
- 添加了OAuthRequestedMatcher,以便Oauth過濾器僅處理Oauth2請求。 我們添加了此內容,以便在基本身份驗證層而不是Oauth 2層將拒絕未授權的請求。 在功能方面,這可能沒有任何區(qū)別,但出于可用性考慮,我們對其進行了添加。 對于客戶端,他們將收到401 HTTP狀態(tài),其中包含此新標頭和舊標頭:
- WWW-Authenticate:基本領域=“領域”
- 使用新的響應標頭,瀏覽器將自動提示用戶輸入用戶名和密碼。 如果您不希望任何其他身份驗證機制訪問該資源,則無需執(zhí)行此步驟。
- 某些瀏覽器(例如Chrome)喜歡在發(fā)出AJAX調用之前發(fā)送OPTIONS請求以查找CORS。 因此,最好始終允許OPTIONS請求。
基本身份驗證安全配置
如前所述,因為我們需要保護令牌提供者端點。
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredpublic void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("USER", "ADMIN");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated().and().httpBasic().and().csrf().disable();}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();} }有幾件事要注意:
- 我們公開了AuthenticationManager bean,以便我們的兩個身份驗證安全適配器可以共享一個身份驗證管理器。
- Spring Security CSRF可與JSP無縫協(xié)作,但對RestAPI來說很麻煩。 因為我們希望將此示例應用程序用作用戶開發(fā)自己的應用程序的基礎,所以我們關閉了CSRF并添加了CORS過濾器,以便可以立即使用它。
測試中
我們嚴格按照Oauth2規(guī)范為每種授權授予類型編寫了一個測試方案。 由于Spring Security Oauth 2是基于Spring Security框架的實現,因此我們的興趣轉向查看如何構造基礎身份驗證和主體。
在總結實驗結果之前,讓我們快速看一下要記錄的內容。
- 對令牌提供者端點的大多數請求都是使用POST請求發(fā)送的,但它們包含用戶憑據作為參數。 即使為了方便起見,我們將此憑據作為url的一部分放置,也切勿在Oauth 2客戶端中執(zhí)行此操作。
- 我們創(chuàng)建了兩個端點/ resources / principal和/ resources / roles來捕獲Oauth 2身份驗證的主體和權限。
這是我們的設置:
| 用戶 | 類型 | 當局 | 憑據 |
| 用戶 | 資源所有者 | ROLE_USER | ? |
| 管理員 | 資源所有者 | ROLE_ADMIN | ? |
| 普通應用 | 客戶 | ROLE_CLIENT | ? |
| 受信任的應用 | 客戶 | ROLE_TRUSTED_CLIENT | ? |
| 贈款類型 | 用戶 | 客戶 | 主要 | 當局 |
| 授權碼 | 用戶 | 普通應用 | 用戶 | ROLE_USER |
| 客戶憑證 | 不適用 | 受信任的應用 | 受信任的應用 | 沒有權限 |
| 隱含的 | 用戶 | 普通應用 | 用戶 | ROLE_USER |
| 資源所有者密碼憑證 | 用戶 | 受信任的應用 | 用戶 | ROLE_USER |
除客戶端憑據外,此結果與預期的相當。 有趣的是,即使客戶端通過客戶端證書檢索Oauth 2令牌,批準的請求仍然沒有任何客戶端權限,而僅具有客戶端證書。 我認為這是有道理的,因為隱式授予類型的令牌無法重用。 這是我們發(fā)現的
翻譯自: https://www.javacodegeeks.com/2016/04/spring-oauth2-jwt-sample.html
總結
以上是生活随笔為你收集整理的带有JWT示例的Spring Oauth2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓单机三国策略游戏(安卓单机三国)
- 下一篇: SpringBoot:与JOOQ合作