javascript
微服务安全Spring Security OAuth2实战
文章目錄
- 一、OAuth2.0介紹
- 1.1 應用場景
- 1.2 基本概念
- 1.3 優缺點
- 二、OAuth2的設計思路
- 2.1 客戶端授權模式
- 授權碼模式
- 簡化(隱式)模式
- 密碼模式
- 客戶端模式
- 2.2 令牌的使用
- 2.3 更新令牌
- 三、Spring Security OAuth2快速開始
- 3.1 授權服務器
- 3.2 整體架構
- 3.3 授權碼模式
- 3.4 簡化模式
- 3.5 密碼模式
- 獲取令牌
- 3.6 客戶端模式
- 3.7 更新令牌
- 3.8 基于redis存儲Token
一、OAuth2.0介紹
OAuth(Open Authorization)是一個關于授權(authorization)的開放網絡標準,允許用戶授權第三方應用訪問他們存儲在另外的服務提供者上的信息,而不需要將用戶名和密碼提供給第三方移動應用或分享他們數據的所有內容。OAuth在全世界得到廣泛應用,目前的版本是2.0版。
OAuth協議:https://tools.ietf.org/html/rfc6749
協議特點:
- 簡單:不管是OAuth服務提供者還是應用開發者,都很易于理解與使用;
- 安全:沒有涉及到用戶密鑰等信息,更安全更靈活;
- 開放:任何服務提供商都可以實現OAuth,任何軟件開發商都可以使用OAuth;
1.1 應用場景
- 原生app授權:app登錄請求后臺接口,為了安全認證,所有請求都帶token信息,如果登錄驗證、請求后臺數據。
- 前后端分離單頁面應用:前后端分離框架,前端請求后臺數據,需要進行oauth2安全認證,比如使用vue、react后者h5開發的app
- 第三方應用授權登錄,比如QQ,微博,微信的授權登錄。
有一個"云沖印"的網站,可以將用戶儲存在Google的照片,沖印出來。用戶為了使用該服務,必須讓"云沖印"讀取自己儲存在Google上的照片。只有得到用戶的授權,Google才會同意"云沖印"讀取這些照片。那么,"云沖印"怎樣獲得用戶的授權呢?
傳統方法是,用戶將自己的Google用戶名和密碼,告訴"云沖印",后者就可以讀取用戶的照片了。這樣的做法有以下幾個嚴重的缺點:
- "云沖印"為了后續的服務,會保存用戶的密碼,這樣很不安全。
- Google不得不部署密碼登錄,而我們知道,單純的密碼登錄并不安全。
- "云沖印"擁有了獲取用戶儲存在Google所有資料的權力,用戶沒法限制"云沖印"獲得授權的范圍和有效期。
- 用戶只有修改密碼,才能收回賦予"云沖印"的權力。但是這樣做,會使得其他所有獲得用戶授權的第三方應用程序全部失效。
- 只要有一個第三方應用程序被破解,就會導致用戶密碼泄漏,以及所有被密碼保護的數據泄漏。
生活中常見的oauth2場景,京東商城(https://www.jd.com/)接入微信開放平臺,可以通過微信登錄。
登錄流程分析:
1.2 基本概念
(1)Third-party application:第三方應用程序,又稱"客戶端"(client),即例子中的"云沖印"。
(2)HTTP service:HTTP服務提供商,簡稱"服務提供商",即例子中的Google。
(3)Resource Owner:資源所有者,又稱"用戶"(user)。
(4)User Agent:用戶代理,比如瀏覽器。
(5)Authorization server:授權服務器,即服務提供商專門用來處理認證授權的服務器。
(6)Resource server:資源服務器,即服務提供商存放用戶生成的資源的服務器。它與授權服務器,可以是同一臺服務器,也可以是不同的服務器。
OAuth的作用就是讓"客戶端"安全可控地獲取"用戶"的授權,與"服務提供商"進行交互。
1.3 優缺點
優點:
- 更安全,客戶端不接觸用戶密碼,服務器端更易集中保護
- 廣泛傳播并被持續采用
- 短壽命和封裝的token
- 資源服務器和授權服務器解耦
- 集中式授權,簡化客戶端
- HTTP/JSON友好,易于請求和傳遞token
- 考慮多種客戶端架構場景
- 客戶可以具有不同的信任級別
缺點:
- 協議框架太寬泛,造成各種實現的兼容性和互操作性差。
- 不是一個認證協議,本身并不能告訴你任何用戶信息。
二、OAuth2的設計思路
OAuth在"客戶端"與"服務提供商"之間,設置了一個授權層(authorization layer)。“客戶端"不能直接登錄"服務提供商”,只能登錄授權層,以此將用戶與客戶端區分開來。"客戶端"登錄授權層所用的令牌(token),與用戶的密碼不同。用戶可以在登錄的時候,指定授權層令牌的權限范圍和有效期,"客戶端"登錄授權層以后,"服務提供商"根據令牌的權限范圍和有效期,向"客戶端"開放用戶儲存的資料。
OAuth 2.0的運行流程如下圖,摘自RFC 6749:
(A)用戶打開客戶端以后,客戶端要求用戶給予授權。
(B)用戶同意給予客戶端授權。
(C)客戶端使用上一步獲得的授權,向授權服務器申請令牌。
(D)授權服務器對客戶端進行認證以后,確認無誤,同意發放令牌。
(E)客戶端使用令牌,向資源服務器申請獲取資源。
(F)資源服務器確認令牌無誤,同意向客戶端開放資源。
令牌(token)與密碼(password)的作用是一樣的,都可以進入系統,但是有三點差異:
- 令牌是短期的,到期會自動失效,用戶自己無法修改。密碼一般長期有效,用戶不修改,就不會發生變化。
- 令牌可以被數據所有者撤銷,會立即失效。密碼一般不允許被他人撤銷。
- 令牌有權限范圍(scope)。對于網絡服務來說,只讀令牌就比讀寫令牌更安全。密碼一般是完整權限。
上面這些設計,保證了令牌既可以讓第三方應用獲得權限,同時又隨時可控,不會危及系統安全。這就是 OAuth 2.0 的優點。
2.1 客戶端授權模式
客戶端必須得到用戶的授權(authorization grant),才能獲得令牌(access token)。OAuth 2.0 對于如何頒發令牌的細節,規定得非常詳細。具體來說,一共分成四種授權類型(authorization grant),即四種頒發令牌的方式,適用于不同的互聯網場景。
- 授權碼模式(authorization code)
- 密碼模式(resource owner password credentials)
- 簡化(隱式)模式(implicit)
- 客戶端模式(client credentials)
不管哪一種授權方式,第三方應用申請令牌之前,都必須先到系統備案,說明自己的身份,然后會拿到兩個身份識別碼:客戶端 ID(client ID)和客戶端密鑰(client secret)。這是為了防止令牌被濫用,沒有備案過的第三方應用,是不會拿到令牌的。
授權碼模式
授權碼(authorization code)方式,指的是第三方應用先申請一個授權碼,然后再用該碼獲取令牌。
這種方式是最常用的流程,安全性也最高,它適用于那些有后端的 Web 應用。授權碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。
適用場景:目前市面上主流的第三方驗證都是采用這種模式。
它的步驟如下:
(A)用戶訪問客戶端,后者將前者導向授權服務器。
(B)用戶選擇是否給予客戶端授權。
(C)假設用戶給予授權,授權服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權碼。
(D)客戶端收到授權碼,附上早先的"重定向URI",向授權服務器申請令牌。這一步是在客戶端的后臺的服務器上完成的,對用戶不可見。
(E)授權服務器核對了授權碼和重定向URI,確認無誤后,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。
1、A網站提供一個鏈接,用戶點擊后就會跳轉到 B 網站,授權用戶數據給 A 網站使用。下面就是 A 網站跳轉 B 網站的一個示意鏈接。
https://b.com/oauth/authorize?response_type=code& #要求返回授權碼(code)client_id=CLIENT_ID& #讓 B 知道是誰在請求 redirect_uri=CALLBACK_URL& #B 接受或拒絕請求后的跳轉網址 scope=read # 要求的授權范圍(這里是只讀)客戶端申請授權的URI,包含以下參數:
- response_type:表示授權類型,必選項,此處的值固定為"code"
- client_id:表示客戶端的ID,必選項
- redirect_uri:表示重定向URI,可選項
- scope:表示申請的權限范圍,可選項
- state:表示客戶端的當前狀態,可以指定任意值,授權服務器會原封不動地返回這個值。
2、用戶跳轉后,B 網站會要求用戶登錄,然后詢問是否同意給予 A 網站授權。用戶表示同意,這時 B 網站就會跳回redirect_uri參數指定的網址。跳轉時,會傳回一個授權碼,就像下面這樣。
https://a.com/callback?code=AUTHORIZATION_CODE #code參數就是授權碼3、A 網站拿到授權碼以后,就可以在后端,向 B 網站請求令牌。 用戶不可見,服務端行為
https://b.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET& # client_id和client_secret用來讓 B 確認 A 的身份,client_secret參數是保密的,因此只能在后端發請求grant_type=authorization_code& # 采用的授權方式是授權碼code=AUTHORIZATION_CODE& # 上一步拿到的授權碼redirect_uri=CALLBACK_URL # 令牌頒發后的回調網址4、B 網站收到請求以后,就會頒發令牌。具體做法是向redirect_uri指定的網址,發送一段 JSON 數據。
{ "access_token":"ACCESS_TOKEN", "token_type":"bearer","expires_in":2592000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":100101,"info":{...} }簡化(隱式)模式
有些 Web 應用是純前端應用,沒有后端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規定了第二種方式,允許直接向前端頒發令牌,這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)“隱藏式”(implicit)。
簡化模式不通過第三方應用程序的服務器,直接在瀏覽器中向授權服務器申請令牌,跳過了"授權碼"這個步驟,所有步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不需要認證。
這種方式把令牌直接傳給前端,是很不安全的。因此,只能用于一些安全要求不高的場景,并且令牌的有效期必須非常短,通常就是會話期間(session)有效,瀏覽器關掉,令牌就失效了。
它的步驟如下:
(A)客戶端將用戶導向授權服務器。
(B)用戶決定是否給于客戶端授權。
(C)假設用戶給予授權,授權服務器將用戶導向客戶端指定的"重定向URI",并在URI的Hash部分包含了訪問令牌。
(D)瀏覽器向資源服務器發出請求,其中不包括上一步收到的Hash值。
(E)資源服務器返回一個網頁,其中包含的代碼可以獲取Hash值中的令牌。
(F)瀏覽器執行上一步獲得的腳本,提取出令牌。
(G)瀏覽器將令牌發給客戶端。
1、A 網站提供一個鏈接,要求用戶跳轉到 B 網站,授權用戶數據給 A 網站使用。
https://b.com/oauth/authorize?response_type=token& # response_type參數為token,表示要求直接返回令牌client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read2、用戶跳轉到 B 網站,登錄后同意給予 A 網站授權。這時,B 網站就會跳回redirect_uri參數指定的跳轉網址,并且把令牌作為 URL 參數,傳給 A 網站。
https://a.com/callback#token=ACCESS_TOKEN #token參數就是令牌,A 網站直接在前端拿到令牌。密碼模式
如果你高度信任某個應用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應用。該應用就使用你的密碼,申請令牌,這種方式稱為"密碼式"(password)。
在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。這通常用在用戶對客戶端高度信任的情況下,比如客戶端是操作系統的一部分,或者由一個著名公司出品。而授權服務器只有在其他授權模式無法執行的情況下,才能考慮使用這種模式。
適用場景:自家公司搭建的授權服務器。
它的步驟如下:
(A)用戶向客戶端提供用戶名和密碼。
(B)客戶端將用戶名和密碼發給授權服務器,向后者請求令牌。
(C)授權服務器確認無誤后,向客戶端提供訪問令牌。
1、 A 網站要求用戶提供 B 網站的用戶名和密碼,拿到以后,A 就直接向 B 請求令牌。整個過程中,客戶端不得保存用戶的密碼。
https://oauth.b.com/token?grant_type=password& # 授權方式是"密碼式"username=USERNAME&password=PASSWORD&client_id=CLIENT_ID2、B 網站驗證身份通過后,直接給出令牌。注意,這時不需要跳轉,而是把令牌放在 JSON 數據里面,作為 HTTP 回應,A 因此拿到令牌。
客戶端模式
客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向"服務提供商"進行授權。
適用于沒有前端的命令行應用,即在命令行下請求令牌。一般用來提供給我們完全信任的服務器端服務。
它的步驟如下:
(A)客戶端向授權服務器進行身份認證,并要求一個訪問令牌。
(B)授權服務器確認無誤后,向客戶端提供訪問令牌。
1、A 應用在命令行向 B 發出請求。
https://oauth.b.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET2、B 網站驗證通過以后,直接返回令牌。
2.2 令牌的使用
A 網站拿到令牌以后,就可以向 B 網站的 API 請求數據了。
此時,每個發到 API 的請求,都必須帶有令牌。具體做法是在請求的頭信息,加上一個Authorization字段,令牌就放在這個字段里面。
curl -H "Authorization: Bearer ACCESS_TOKEN" \"https://api.b.com"也可以通過添加請求參數access_token請求數據。
2.3 更新令牌
令牌的有效期到了,如果讓用戶重新走一遍上面的流程,再申請一個新的令牌,很可能體驗不好,而且也沒有必要。OAuth 2.0 允許用戶自動更新令牌。
具體方法是,B 網站頒發令牌的時候,一次性頒發兩個令牌,一個用于獲取數據,另一個用于獲取新的令牌(refresh token 字段)。令牌到期前,用戶使用 refresh token 發一個請求,去更新令牌。
三、Spring Security OAuth2快速開始
Spring Security是一個能夠為基于Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。
Spring Security 主要實現了Authentication(認證,解決who are you? ) 和 Access Control(訪問控制,也就是what are you allowed to do?,也稱為Authorization)。
Spring Security在架構上將認證與授權分離,并提供了擴展點。
認證(Authentication) :用戶認證就是判斷一個用戶的身份是否合法的過程,用戶去訪問系統資源時系統要求驗證用戶的身份信息,身份合法方可繼續訪問,不合法則拒絕訪問。常見的用戶身份認證方式有:用戶名密碼登錄,二維碼登錄,手機短信登錄,指紋認證等方式。
授權(Authorization): 授權是用戶認證通過根據用戶的權限來控制用戶訪問資源的過程,擁有資源的訪問權限則正常訪問,沒有權限則拒絕訪問。
將OAuth2和Spring Security集成,就可以得到一套完整的安全解決方案。我們可以通過Spring Security OAuth2構建一個授權服務器來驗證用戶身份以提供access_token,并使用這個access_token來從資源服務器請求數據。
3.1 授權服務器
- Authorize Endpoint :授權端點,進行授權
- Token Endpoint :令牌端點,經過授權拿到對應的Token
- Introspection Endpoint :校驗端點,校驗Token的合法性
- Revocation Endpoint :撤銷端點,撤銷授權
3.2 整體架構
流程:
1、用戶訪問,此時沒有Token。Oauth2RestTemplate會報錯,這個報錯信息會被Oauth2ClientContextFilter捕獲并重定向到授權服務器。
2、授權服務器通過Authorization Endpoint進行授權,并通過AuthorizationServerTokenServices生成授權碼并返回給客戶端。
3、客戶端拿到授權碼去授權服務器通過Token Endpoint調用AuthorizationServerTokenServices生成Token并返回給客戶端
4、客戶端拿到Token去資源服務器訪問資源,一般會通過Oauth2AuthenticationManager調用ResourceServerTokenServices進行校驗。校驗通過可以獲取資源。
3.3 授權碼模式
1、引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency><dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>2.3.4.RELEASE</version> </dependency>或者 引入spring cloud oauth2依賴:
<!--spring-mvc依賴--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId> </dependency><!-- spring cloud --> <dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR8</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement>配置 spring security:
@Configuration @EnableWebSecurity // 默認開啟,可以不寫 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().permitAll().and().authorizeRequests().antMatchers("/oauth/**").permitAll().anyRequest().authenticated().and().logout().permitAll().and().cors().disable();}} @Service public class UserService implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {String password = passwordEncoder.encode("123456");return new User("jihu", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));} } @RestController @RequestMapping("/user") public class UserController {@RequestMapping("/getCurrentUser")public Object getCurrentUser(Authentication authentication) {return authentication.getPrincipal();} }配置授權服務器:
@Configuration @EnableAuthorizationServer // 這個注解必須加上,否則訪問測試地址404 public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權碼模式 // //http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all // // 簡化模式 http://localhost:8080/oauth/authorize?response_type=token&client_id=client&redirect_uri=http://www.baidu.com&scope=allclients.inMemory()// 配置client_id.withClient("client")// 配置client_secret.secret(passwordEncoder.encode("123123"))//配置訪問token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授權成功后跳轉.redirectUris("http://www.baidu.com")//配置申請的權限范圍.scopes("all")/*** 配置grant_type,表示授權類型** authorization_code:授權碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code");} }配置資源服務器:
@Configuration @EnableResourceServer // 配置資源服務器 public class ResourceServiceConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated()// 訪問用戶資源的時候需要認證 .and().requestMatchers().antMatchers("/user/**");} }然后我們啟動這個springBoot項目:
測試:
http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
或者
http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
然后會跳轉到登錄頁面:
輸入UserService#loadUserByUsername方法中配置的用戶名和密碼進行登錄,登錄之后進入:
選擇Approve,點擊授權獲取授權碼并跳轉到重定向頁面:
根據授權碼通過post請求(默認不支持通過get請求)獲取:
此時我們已經成功獲取到了access_token,就可以使用這個token來訪問服務了。
我們來訪問:http://localhost:8080/user/getCurrentUser
方式一: 請求時添加一個Header參數:
key:Authorization
value:bearer access_token
訪問成功,成功獲取到了用戶信息:
方式二: 請求時在url中添加一個access_token參數
3.4 簡化模式
authorizedGrantType添加implicit:
測試:http://localhost:8080/oauth/authorize?client_id=client&response_type=token&scope=all&redirect_uri=http://www.baidu.com
登錄之后進入授權頁面,確定授權后瀏覽器會重定向到指定路徑,并以Hash的形式存放在重定向uri的fargment中:
3.5 密碼模式
修改WebSecurityConfig,增加AuthenticationManager:
/*** Spring Security 配置*/ @Configuration @EnableWebSecurity // 默認開啟,可以不寫 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().permitAll().and().authorizeRequests().antMatchers("/oauth/**").permitAll().anyRequest().authenticated().and().logout().permitAll().and().cors().disable();}// 支持密碼模式@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();} }修改AuthorizationServerConfig配置:
- 注入AuthenticationManager
- 重寫configure(AuthorizationServerEndpointsConfigurer endpoints)方法,讓其支持密碼模式
- authorizedGrantTypes添加密碼模式
- 通過瀏覽器測試,需要配置支持get請求和表單驗證:
獲取令牌
通過瀏覽器測試,需要配置支持get請求和表單驗證:
測試:http://localhost:8080/oauth/token?username=jihu&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all
已經成功獲取到了access_token。
通過Postman測試:
訪問資源:
http://localhost:8080/user/getCurrentUser?access_token=804951ba-accf-4004-9af8-23896dfcf138
3.6 客戶端模式
添加分配類型:
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權碼模式 // //http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all // // 簡化模式 http://localhost:8080/oauth/authorize?response_type=token&client_id=client&redirect_uri=http://www.baidu.com&scope=allclients.inMemory()// 配置client_id.withClient("client")// 配置client_secret.secret(passwordEncoder.encode("123123"))//配置訪問token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授權成功后跳轉.redirectUris("http://www.baidu.com")//配置申請的權限范圍.scopes("all")/*** 配置grant_type,表示授權類型** authorization_code:授權碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials");}獲取令牌:
http://localhost:8080/oauth/token?username=jihu&password=123456&grant_type=client_credentials&client_id=client&client_secret=123123&scope=all
3.7 更新令牌
使用oauth2時,如果令牌失效了,可以使用刷新令牌通過refresh_token的授權模式再次獲取access_token。只需修改認證服務器的配置,添加refresh_token的授權模式即可。
修改授權服務器配置,增加refresh_token配置:
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權碼模式 // //http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all // // 簡化模式 http://localhost:8080/oauth/authorize?response_type=token&client_id=client&redirect_uri=http://www.baidu.com&scope=allclients.inMemory()// 配置client_id.withClient("client")// 配置client_secret.secret(passwordEncoder.encode("123123"))//配置訪問token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授權成功后跳轉.redirectUris("http://www.baidu.com")//配置申請的權限范圍.scopes("all")/*** 配置grant_type,表示授權類型** authorization_code:授權碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token"); }通過密碼模式測試:
然后我們通過整個refresh_token值來重新獲取access_token:
發現訪問出現如下錯誤:
注意,此時需要加一些配置:
- 需要配置userDetailsService,我們之前有定義一個UserService實現了這個接口:
- 配置UserDetailsService
測試:
通過瀏覽器訪問:http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=9ee21cbf-0c12-40e9-8426-a4184be5d61b
拓展: 可以設置refresh_token是否只生效一次:
3.8 基于redis存儲Token
引入依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId> </dependency>修改application.yaml:
spring:application:name: mall-authcenterredis:host: 127.0.0.1database: 0server:port: 8080編寫redis配置類:
@Configuration public class RedisConfig {@Autowiredprivate RedisConnectionFactory redisConnectionFactory;@Beanpublic TokenStore tokenStore() {return new RedisTokenStore(redisConnectionFactory);} }在授權服務器配置中指定令牌的存儲策略為Redis :
// AuthorizationServerConfig配置類: @Autowired private TokenStore tokenStore;// 配置支持GET,POST請求 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManagerBean) //使用密碼模式需要配置.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST) //支持GET,POST請求.reuseRefreshTokens(false) //refresh_token是否重復使用.userDetailsService(userService) //刷新令牌授權包含對用戶信息的檢查.tokenStore(tokenStore); //指定token存儲到redis }配置完成后獲取access_token,然后查看Redis發現生成了相關數據:
總結
以上是生活随笔為你收集整理的微服务安全Spring Security OAuth2实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 清北+华五!中国最强的7所大学!北京重点
- 下一篇: android P 不让应用持有Wake