日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

微服务安全Spring Security OAuth2实战

發(fā)布時間:2024/1/18 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微服务安全Spring Security OAuth2实战 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 一、OAuth2.0介紹
    • 1.1 應(yīng)用場景
    • 1.2 基本概念
    • 1.3 優(yōu)缺點(diǎn)
  • 二、OAuth2的設(shè)計思路
    • 2.1 客戶端授權(quán)模式
      • 授權(quán)碼模式
      • 簡化(隱式)模式
      • 密碼模式
      • 客戶端模式
    • 2.2 令牌的使用
    • 2.3 更新令牌
  • 三、Spring Security OAuth2快速開始
    • 3.1 授權(quán)服務(wù)器
    • 3.2 整體架構(gòu)
    • 3.3 授權(quán)碼模式
    • 3.4 簡化模式
    • 3.5 密碼模式
      • 獲取令牌
    • 3.6 客戶端模式
    • 3.7 更新令牌
    • 3.8 基于redis存儲Token

一、OAuth2.0介紹

OAuth(Open Authorization)是一個關(guān)于授權(quán)(authorization)的開放網(wǎng)絡(luò)標(biāo)準(zhǔn),允許用戶授權(quán)第三方應(yīng)用訪問他們存儲在另外的服務(wù)提供者上的信息,而不需要將用戶名和密碼提供給第三方移動應(yīng)用或分享他們數(shù)據(jù)的所有內(nèi)容。OAuth在全世界得到廣泛應(yīng)用,目前的版本是2.0版。

OAuth協(xié)議:https://tools.ietf.org/html/rfc6749

協(xié)議特點(diǎn):

  • 簡單:不管是OAuth服務(wù)提供者還是應(yīng)用開發(fā)者,都很易于理解與使用;
  • 安全:沒有涉及到用戶密鑰等信息,更安全更靈活;
  • 開放:任何服務(wù)提供商都可以實(shí)現(xiàn)OAuth,任何軟件開發(fā)商都可以使用OAuth;

1.1 應(yīng)用場景

  • 原生app授權(quán):app登錄請求后臺接口,為了安全認(rèn)證,所有請求都帶token信息,如果登錄驗(yàn)證、請求后臺數(shù)據(jù)。
  • 前后端分離單頁面應(yīng)用:前后端分離框架,前端請求后臺數(shù)據(jù),需要進(jìn)行oauth2安全認(rèn)證,比如使用vue、react后者h(yuǎn)5開發(fā)的app
  • 第三方應(yīng)用授權(quán)登錄,比如QQ,微博,微信的授權(quán)登錄。

有一個"云沖印"的網(wǎng)站,可以將用戶儲存在Google的照片,沖印出來。用戶為了使用該服務(wù),必須讓"云沖印"讀取自己儲存在Google上的照片。只有得到用戶的授權(quán),Google才會同意"云沖印"讀取這些照片。那么,"云沖印"怎樣獲得用戶的授權(quán)呢?

傳統(tǒng)方法是,用戶將自己的Google用戶名和密碼,告訴"云沖印",后者就可以讀取用戶的照片了。這樣的做法有以下幾個嚴(yán)重的缺點(diǎn):

  • "云沖印"為了后續(xù)的服務(wù),會保存用戶的密碼,這樣很不安全。
  • Google不得不部署密碼登錄,而我們知道,單純的密碼登錄并不安全。
  • "云沖印"擁有了獲取用戶儲存在Google所有資料的權(quán)力,用戶沒法限制"云沖印"獲得授權(quán)的范圍和有效期。
  • 用戶只有修改密碼,才能收回賦予"云沖印"的權(quán)力。但是這樣做,會使得其他所有獲得用戶授權(quán)的第三方應(yīng)用程序全部失效。
  • 只要有一個第三方應(yīng)用程序被破解,就會導(dǎo)致用戶密碼泄漏,以及所有被密碼保護(hù)的數(shù)據(jù)泄漏。


生活中常見的oauth2場景,京東商城(https://www.jd.com/)接入微信開放平臺,可以通過微信登錄。


登錄流程分析:

1.2 基本概念

(1)Third-party application:第三方應(yīng)用程序,又稱"客戶端"(client),即例子中的"云沖印"。
(2)HTTP service:HTTP服務(wù)提供商,簡稱"服務(wù)提供商",即例子中的Google。
(3)Resource Owner:資源所有者,又稱"用戶"(user)。
(4)User Agent:用戶代理,比如瀏覽器。
(5)Authorization server:授權(quán)服務(wù)器,即服務(wù)提供商專門用來處理認(rèn)證授權(quán)的服務(wù)器。
(6)Resource server:資源服務(wù)器,即服務(wù)提供商存放用戶生成的資源的服務(wù)器。它與授權(quán)服務(wù)器,可以是同一臺服務(wù)器,也可以是不同的服務(wù)器。

OAuth的作用就是讓"客戶端"安全可控地獲取"用戶"的授權(quán),與"服務(wù)提供商"進(jìn)行交互。

1.3 優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 更安全,客戶端不接觸用戶密碼,服務(wù)器端更易集中保護(hù)
  • 廣泛傳播并被持續(xù)采用
  • 短壽命和封裝的token
  • 資源服務(wù)器和授權(quán)服務(wù)器解耦
  • 集中式授權(quán),簡化客戶端
  • HTTP/JSON友好,易于請求和傳遞token
  • 考慮多種客戶端架構(gòu)場景
  • 客戶可以具有不同的信任級別

缺點(diǎn):

  • 協(xié)議框架太寬泛,造成各種實(shí)現(xiàn)的兼容性和互操作性差。
  • 不是一個認(rèn)證協(xié)議,本身并不能告訴你任何用戶信息。

二、OAuth2的設(shè)計思路

OAuth在"客戶端"與"服務(wù)提供商"之間,設(shè)置了一個授權(quán)層(authorization layer)。“客戶端"不能直接登錄"服務(wù)提供商”,只能登錄授權(quán)層,以此將用戶與客戶端區(qū)分開來。"客戶端"登錄授權(quán)層所用的令牌(token),與用戶的密碼不同。用戶可以在登錄的時候,指定授權(quán)層令牌的權(quán)限范圍和有效期,"客戶端"登錄授權(quán)層以后,"服務(wù)提供商"根據(jù)令牌的權(quán)限范圍和有效期,向"客戶端"開放用戶儲存的資料。

OAuth 2.0的運(yùn)行流程如下圖,摘自RFC 6749:

(A)用戶打開客戶端以后,客戶端要求用戶給予授權(quán)。
(B)用戶同意給予客戶端授權(quán)。
(C)客戶端使用上一步獲得的授權(quán),向授權(quán)服務(wù)器申請令牌。
(D)授權(quán)服務(wù)器對客戶端進(jìn)行認(rèn)證以后,確認(rèn)無誤,同意發(fā)放令牌。
(E)客戶端使用令牌,向資源服務(wù)器申請獲取資源。
(F)資源服務(wù)器確認(rèn)令牌無誤,同意向客戶端開放資源。

令牌(token)密碼(password)的作用是一樣的,都可以進(jìn)入系統(tǒng),但是有三點(diǎn)差異:

  • 令牌是短期的,到期會自動失效,用戶自己無法修改。密碼一般長期有效,用戶不修改,就不會發(fā)生變化。
  • 令牌可以被數(shù)據(jù)所有者撤銷,會立即失效。密碼一般不允許被他人撤銷。
  • 令牌有權(quán)限范圍(scope)。對于網(wǎng)絡(luò)服務(wù)來說,只讀令牌就比讀寫令牌更安全。密碼一般是完整權(quán)限。

上面這些設(shè)計,保證了令牌既可以讓第三方應(yīng)用獲得權(quán)限,同時又隨時可控,不會危及系統(tǒng)安全。這就是 OAuth 2.0 的優(yōu)點(diǎn)。

2.1 客戶端授權(quán)模式

客戶端必須得到用戶的授權(quán)(authorization grant),才能獲得令牌(access token)。OAuth 2.0 對于如何頒發(fā)令牌的細(xì)節(jié),規(guī)定得非常詳細(xì)。具體來說,一共分成四種授權(quán)類型(authorization grant),即四種頒發(fā)令牌的方式,適用于不同的互聯(lián)網(wǎng)場景。

  • 授權(quán)碼模式(authorization code)
  • 密碼模式(resource owner password credentials)
  • 簡化(隱式)模式(implicit)
  • 客戶端模式(client credentials)

不管哪一種授權(quán)方式,第三方應(yīng)用申請令牌之前,都必須先到系統(tǒng)備案,說明自己的身份,然后會拿到兩個身份識別碼:客戶端 ID(client ID)和客戶端密鑰(client secret)。這是為了防止令牌被濫用,沒有備案過的第三方應(yīng)用,是不會拿到令牌的。

授權(quán)碼模式

授權(quán)碼(authorization code)方式,指的是第三方應(yīng)用先申請一個授權(quán)碼,然后再用該碼獲取令牌。

這種方式是最常用的流程,安全性也最高,它適用于那些有后端的 Web 應(yīng)用。授權(quán)碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務(wù)器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。

適用場景:目前市面上主流的第三方驗(yàn)證都是采用這種模式。


它的步驟如下:

(A)用戶訪問客戶端,后者將前者導(dǎo)向授權(quán)服務(wù)器。

(B)用戶選擇是否給予客戶端授權(quán)。

(C)假設(shè)用戶給予授權(quán),授權(quán)服務(wù)器將用戶導(dǎo)向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權(quán)碼。

(D)客戶端收到授權(quán)碼,附上早先的"重定向URI",向授權(quán)服務(wù)器申請令牌。這一步是在客戶端的后臺的服務(wù)器上完成的,對用戶不可見。

(E)授權(quán)服務(wù)器核對了授權(quán)碼和重定向URI,確認(rèn)無誤后,向客戶端發(fā)送訪問令牌(access token)和更新令牌(refresh token)。

1、A網(wǎng)站提供一個鏈接,用戶點(diǎn)擊后就會跳轉(zhuǎn)到 B 網(wǎng)站,授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用。下面就是 A 網(wǎng)站跳轉(zhuǎn) B 網(wǎng)站的一個示意鏈接。

https://b.com/oauth/authorize?response_type=code& #要求返回授權(quán)碼(code)client_id=CLIENT_ID& #讓 B 知道是誰在請求 redirect_uri=CALLBACK_URL& #B 接受或拒絕請求后的跳轉(zhuǎn)網(wǎng)址 scope=read # 要求的授權(quán)范圍(這里是只讀)

客戶端申請授權(quán)的URI,包含以下參數(shù):

  • response_type:表示授權(quán)類型,必選項(xiàng),此處的值固定為"code"
  • client_id:表示客戶端的ID,必選項(xiàng)
  • redirect_uri:表示重定向URI,可選項(xiàng)
  • scope:表示申請的權(quán)限范圍,可選項(xiàng)
  • state:表示客戶端的當(dāng)前狀態(tài),可以指定任意值,授權(quán)服務(wù)器會原封不動地返回這個值。

2、用戶跳轉(zhuǎn)后,B 網(wǎng)站會要求用戶登錄,然后詢問是否同意給予 A 網(wǎng)站授權(quán)。用戶表示同意,這時 B 網(wǎng)站就會跳回redirect_uri參數(shù)指定的網(wǎng)址。跳轉(zhuǎn)時,會傳回一個授權(quán)碼,就像下面這樣。

https://a.com/callback?code=AUTHORIZATION_CODE #code參數(shù)就是授權(quán)碼

3、A 網(wǎng)站拿到授權(quán)碼以后,就可以在后端,向 B 網(wǎng)站請求令牌。 用戶不可見,服務(wù)端行為

https://b.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET& # client_id和client_secret用來讓 B 確認(rèn) A 的身份,client_secret參數(shù)是保密的,因此只能在后端發(fā)請求grant_type=authorization_code& # 采用的授權(quán)方式是授權(quán)碼code=AUTHORIZATION_CODE& # 上一步拿到的授權(quán)碼redirect_uri=CALLBACK_URL # 令牌頒發(fā)后的回調(diào)網(wǎng)址

4、B 網(wǎng)站收到請求以后,就會頒發(fā)令牌。具體做法是向redirect_uri指定的網(wǎng)址,發(fā)送一段 JSON 數(shù)據(jù)。

{ "access_token":"ACCESS_TOKEN", "token_type":"bearer","expires_in":2592000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":100101,"info":{...} }

簡化(隱式)模式

有些 Web 應(yīng)用是純前端應(yīng)用,沒有后端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規(guī)定了第二種方式,允許直接向前端頒發(fā)令牌,這種方式?jīng)]有授權(quán)碼這個中間步驟,所以稱為(授權(quán)碼)“隱藏式”(implicit)。

簡化模式不通過第三方應(yīng)用程序的服務(wù)器,直接在瀏覽器中向授權(quán)服務(wù)器申請令牌,跳過了"授權(quán)碼"這個步驟,所有步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不需要認(rèn)證。

這種方式把令牌直接傳給前端,是很不安全的。因此,只能用于一些安全要求不高的場景,并且令牌的有效期必須非常短,通常就是會話期間(session)有效,瀏覽器關(guān)掉,令牌就失效了。

它的步驟如下:

(A)客戶端將用戶導(dǎo)向授權(quán)服務(wù)器。

(B)用戶決定是否給于客戶端授權(quán)。

(C)假設(shè)用戶給予授權(quán),授權(quán)服務(wù)器將用戶導(dǎo)向客戶端指定的"重定向URI",并在URI的Hash部分包含了訪問令牌。

(D)瀏覽器向資源服務(wù)器發(fā)出請求,其中不包括上一步收到的Hash值。

(E)資源服務(wù)器返回一個網(wǎng)頁,其中包含的代碼可以獲取Hash值中的令牌。

(F)瀏覽器執(zhí)行上一步獲得的腳本,提取出令牌。

(G)瀏覽器將令牌發(fā)給客戶端。

1、A 網(wǎng)站提供一個鏈接,要求用戶跳轉(zhuǎn)到 B 網(wǎng)站,授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用。

https://b.com/oauth/authorize?response_type=token& # response_type參數(shù)為token,表示要求直接返回令牌client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

2、用戶跳轉(zhuǎn)到 B 網(wǎng)站,登錄后同意給予 A 網(wǎng)站授權(quán)。這時,B 網(wǎng)站就會跳回redirect_uri參數(shù)指定的跳轉(zhuǎn)網(wǎng)址,并且把令牌作為 URL 參數(shù),傳給 A 網(wǎng)站。

https://a.com/callback#token=ACCESS_TOKEN #token參數(shù)就是令牌,A 網(wǎng)站直接在前端拿到令牌。

密碼模式

如果你高度信任某個應(yīng)用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應(yīng)用。該應(yīng)用就使用你的密碼,申請令牌,這種方式稱為"密碼式"(password)。

在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。這通常用在用戶對客戶端高度信任的情況下,比如客戶端是操作系統(tǒng)的一部分,或者由一個著名公司出品。而授權(quán)服務(wù)器只有在其他授權(quán)模式無法執(zhí)行的情況下,才能考慮使用這種模式。

適用場景:自家公司搭建的授權(quán)服務(wù)器。


它的步驟如下:

(A)用戶向客戶端提供用戶名和密碼。
(B)客戶端將用戶名和密碼發(fā)給授權(quán)服務(wù)器,向后者請求令牌。
(C)授權(quán)服務(wù)器確認(rèn)無誤后,向客戶端提供訪問令牌。

1、 A 網(wǎng)站要求用戶提供 B 網(wǎng)站的用戶名和密碼,拿到以后,A 就直接向 B 請求令牌。整個過程中,客戶端不得保存用戶的密碼。

https://oauth.b.com/token?grant_type=password& # 授權(quán)方式是"密碼式"username=USERNAME&password=PASSWORD&client_id=CLIENT_ID

2、B 網(wǎng)站驗(yàn)證身份通過后,直接給出令牌。注意,這時不需要跳轉(zhuǎn),而是把令牌放在 JSON 數(shù)據(jù)里面,作為 HTTP 回應(yīng),A 因此拿到令牌。

客戶端模式

客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向"服務(wù)提供商"進(jìn)行授權(quán)。

適用于沒有前端的命令行應(yīng)用,即在命令行下請求令牌。一般用來提供給我們完全信任的服務(wù)器端服務(wù)。


它的步驟如下:

(A)客戶端向授權(quán)服務(wù)器進(jìn)行身份認(rèn)證,并要求一個訪問令牌。
(B)授權(quán)服務(wù)器確認(rèn)無誤后,向客戶端提供訪問令牌。

1、A 應(yīng)用在命令行向 B 發(fā)出請求。

https://oauth.b.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

2、B 網(wǎng)站驗(yàn)證通過以后,直接返回令牌。

2.2 令牌的使用

A 網(wǎng)站拿到令牌以后,就可以向 B 網(wǎng)站的 API 請求數(shù)據(jù)了。

此時,每個發(fā)到 API 的請求,都必須帶有令牌。具體做法是在請求的頭信息,加上一個Authorization字段,令牌就放在這個字段里面。

curl -H "Authorization: Bearer ACCESS_TOKEN" \"https://api.b.com"

也可以通過添加請求參數(shù)access_token請求數(shù)據(jù)。

2.3 更新令牌

令牌的有效期到了,如果讓用戶重新走一遍上面的流程,再申請一個新的令牌,很可能體驗(yàn)不好,而且也沒有必要。OAuth 2.0 允許用戶自動更新令牌。


具體方法是,B 網(wǎng)站頒發(fā)令牌的時候,一次性頒發(fā)兩個令牌,一個用于獲取數(shù)據(jù),另一個用于獲取新的令牌(refresh token 字段)。令牌到期前,用戶使用 refresh token 發(fā)一個請求,去更新令牌。

https://b.com/oauth/token?grant_type=refresh_token& # grant_type參數(shù)為refresh_token表示要求更新令牌client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN # 用于更新令牌的令牌

三、Spring Security OAuth2快速開始

Spring Security是一個能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架

Spring Security 主要實(shí)現(xiàn)了Authentication(認(rèn)證,解決who are you? )Access Control(訪問控制,也就是what are you allowed to do?,也稱為Authorization)

Spring Security在架構(gòu)上將認(rèn)證與授權(quán)分離,并提供了擴(kuò)展點(diǎn)。

認(rèn)證(Authentication) :用戶認(rèn)證就是判斷一個用戶的身份是否合法的過程,用戶去訪問系統(tǒng)資源時系統(tǒng)要求驗(yàn)證用戶的身份信息,身份合法方可繼續(xù)訪問,不合法則拒絕訪問。常見的用戶身份認(rèn)證方式有:用戶名密碼登錄,二維碼登錄,手機(jī)短信登錄,指紋認(rèn)證等方式。

授權(quán)(Authorization): 授權(quán)是用戶認(rèn)證通過根據(jù)用戶的權(quán)限來控制用戶訪問資源的過程,擁有資源的訪問權(quán)限則正常訪問,沒有權(quán)限則拒絕訪問。

將OAuth2和Spring Security集成,就可以得到一套完整的安全解決方案。我們可以通過Spring Security OAuth2構(gòu)建一個授權(quán)服務(wù)器來驗(yàn)證用戶身份以提供access_token,并使用這個access_token來從資源服務(wù)器請求數(shù)據(jù)。

3.1 授權(quán)服務(wù)器

  • Authorize Endpoint :授權(quán)端點(diǎn),進(jìn)行授權(quán)
  • Token Endpoint :令牌端點(diǎn),經(jīng)過授權(quán)拿到對應(yīng)的Token
  • Introspection Endpoint :校驗(yàn)端點(diǎn),校驗(yàn)Token的合法性
  • Revocation Endpoint :撤銷端點(diǎn),撤銷授權(quán)

3.2 整體架構(gòu)


流程:
1、用戶訪問,此時沒有Token。Oauth2RestTemplate會報錯,這個報錯信息會被Oauth2ClientContextFilter捕獲并重定向到授權(quán)服務(wù)器。

2、授權(quán)服務(wù)器通過Authorization Endpoint進(jìn)行授權(quán),并通過AuthorizationServerTokenServices生成授權(quán)碼并返回給客戶端。

3、客戶端拿到授權(quán)碼去授權(quán)服務(wù)器通過Token Endpoint調(diào)用AuthorizationServerTokenServices生成Token并返回給客戶端

4、客戶端拿到Token去資源服務(wù)器訪問資源,一般會通過Oauth2AuthenticationManager調(diào)用ResourceServerTokenServices進(jìn)行校驗(yàn)。校驗(yàn)通過可以獲取資源。

3.3 授權(quán)碼模式

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 // 默認(rèn)開啟,可以不寫 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();} }

配置授權(quán)服務(wù)器:

@Configuration @EnableAuthorizationServer // 這個注解必須加上,否則訪問測試地址404 public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code");} }

配置資源服務(wù)器:

@Configuration @EnableResourceServer // 配置資源服務(wù)器 public class ResourceServiceConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated()// 訪問用戶資源的時候需要認(rèn)證 .and().requestMatchers().antMatchers("/user/**");} }

然后我們啟動這個springBoot項(xiàng)目:

測試:
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

然后會跳轉(zhuǎn)到登錄頁面:

輸入UserService#loadUserByUsername方法中配置的用戶名和密碼進(jìn)行登錄,登錄之后進(jìn)入:

選擇Approve,點(diǎn)擊授權(quán)獲取授權(quán)碼并跳轉(zhuǎn)到重定向頁面:

根據(jù)授權(quán)碼通過post請求(默認(rèn)不支持通過get請求)獲取:

此時我們已經(jīng)成功獲取到了access_token,就可以使用這個token來訪問服務(wù)了。

我們來訪問:http://localhost:8080/user/getCurrentUser

方式一: 請求時添加一個Header參數(shù):

key:Authorization

value:bearer access_token

訪問成功,成功獲取到了用戶信息:

方式二: 請求時在url中添加一個access_token參數(shù)

http://localhost:8080/user/getCurrentUser?access_token=22adced1-82cd-4b9d-b590-824bec1b602f

3.4 簡化模式

authorizedGrantType添加implicit:

// AuthorizationServerConfig類 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit"); }

測試:http://localhost:8080/oauth/authorize?client_id=client&response_type=token&scope=all&redirect_uri=http://www.baidu.com

登錄之后進(jìn)入授權(quán)頁面,確定授權(quán)后瀏覽器會重定向到指定路徑,并以Hash的形式存放在重定向uri的fargment中:

3.5 密碼模式

修改WebSecurityConfig,增加AuthenticationManager:

/*** Spring Security 配置*/ @Configuration @EnableWebSecurity // 默認(rèn)開啟,可以不寫 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請求和表單驗(yàn)證:
@Configuration @EnableAuthorizationServer // 這個注解必須加上 public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManagerBean;// 配置支持GET,POST請求@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManagerBean) //使用密碼模式需要配置.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); //支持GET,POST請求}// 配置允許表單認(rèn)證@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.allowFormAuthenticationForClients();}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit", "password");} }

獲取令牌

通過瀏覽器測試,需要配置支持get請求和表單驗(yàn)證:

測試:http://localhost:8080/oauth/token?username=jihu&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all


已經(jīng)成功獲取到了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 {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* 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的授權(quán)模式再次獲取access_token。只需修改認(rèn)證服務(wù)器的配置,添加refresh_token的授權(quán)模式即可。

修改授權(quán)服務(wù)器配置,增加refresh_token配置:

@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token"); }

通過密碼模式測試:


然后我們通過整個refresh_token值來重新獲取access_token:

發(fā)現(xiàn)訪問出現(xiàn)如下錯誤:

注意,此時需要加一些配置:

  • 需要配置userDetailsService,我們之前有定義一個UserService實(shí)現(xiàn)了這個接口:
@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"));} } @Configuration @EnableAuthorizationServer // 這個注解必須加上 public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Lazy@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManagerBean;@Autowiredprivate UserService userService;// 配置支持GET,POST請求@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManagerBean) //使用密碼模式需要配置.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST) //支持GET,POST請求.userDetailsService(userService); //設(shè)置userDetailsService刷新token時候會用到}// 配置允許表單認(rèn)證@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.allowFormAuthenticationForClients();}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//授權(quán)碼模式 // //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,用于授權(quán)成功后跳轉(zhuǎn).redirectUris("http://www.baidu.com")//配置申請的權(quán)限范圍.scopes("all")/*** 配置grant_type,表示授權(quán)類型** authorization_code:授權(quán)碼模式* implicit:簡化模式* password:密碼模式* client_credentials: 客戶端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token");} }
  • 配置UserDetailsService
/*** Spring Security 配置*/ @Configuration @EnableWebSecurity // 默認(rèn)開啟,可以不寫 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserService userService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 獲取用戶信息auth.userDetailsService(userService);}@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();} }

測試:

通過瀏覽器訪問:http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=9ee21cbf-0c12-40e9-8426-a4184be5d61b

拓展: 可以設(shè)置refresh_token是否只生效一次:

// AuthorizationServerConfig配置類 // 配置支持GET,POST請求 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManagerBean) //使用密碼模式需要配置.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST) //支持GET,POST請求.reuseRefreshTokens(false) //refresh_token是否重復(fù)使用.userDetailsService(userService); //刷新令牌授權(quán)包含對用戶信息的檢查}

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);} }

在授權(quán)服務(wù)器配置中指定令牌的存儲策略為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是否重復(fù)使用.userDetailsService(userService) //刷新令牌授權(quán)包含對用戶信息的檢查.tokenStore(tokenStore); //指定token存儲到redis }

配置完成后獲取access_token,然后查看Redis發(fā)現(xiàn)生成了相關(guān)數(shù)據(jù):

總結(jié)

以上是生活随笔為你收集整理的微服务安全Spring Security OAuth2实战的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 九九九视频在线观看 | 99热99热| 少妇毛片 | 中文在线资源天堂 | 欧美色综合网 | 久久久久久久人妻无码中文字幕爆 | 欧美毛片免费看 | ,午夜性刺激免费看视频 | 日本精品影院 | 国产成人免费 | 亚洲制服另类 | 国产精品一区二区三区线羞羞网站 | 美女av免费看| 激情久久网 | 久久爱综合 | 国产精品av在线免费观看 | 91综合精品 | 国产啪视频 | 欧美黑人又粗又大又爽免费 | 友田真希一区二区 | 亚洲我射av| 日韩精选 | 一本加勒比北条麻妃 | 爱草av| 噼里啪啦国语版在线观看 | 岛国av免费在线 | 午夜日韩在线观看 | 日日干日日草 | 高清18麻豆| 日韩精品一区在线视频 | 亚洲一级理论片 | 中文字幕第一页在线 | 偷拍超碰 | 污片视频在线观看 | www久久com | 一级伦理农村妇女愉情 | 桃色成人| 黄网站色 | 欧美日韩字幕 | 大桥未久在线视频 | 国产精品久久久久久吹潮 | 久久瑟瑟 | 日韩成人精品一区二区 | 亚洲热热| 日韩精品欧美 | 亚洲av综合色区无码二区爱av | 中文字幕免费在线播放 | 性一交一乱一色一免费无遮挡 | 51啪影院 | 韩国一区二区三区四区 | 成人xxx| 操碰av | 熟女人妻aⅴ一区二区三区60路 | 亚洲做受高潮 | 亚洲综合精品视频 | 琪琪午夜伦理影院7777 | 免费看黄色一级片 | 国产伦理在线观看 | 永久在线 | 中文字幕第一页在线视频 | 欧美午夜精品久久久久久人妖 | 成人在线观看免费爱爱 | 精品一区电影 | 精品色哟哟 | 亚洲国产成人一区二区精品区 | 久久人久久 | 国产高潮久久久 | 免费色片 | 国产综合视频在线观看 | 国产永久免费 | av永久免费在线观看 | 91蝌蚪91密月 | 爱情岛亚洲品质自拍极速福利网站 | 自拍偷拍第二页 | 天天碰天天 | 日日爱影视 | 亚洲av无码成人精品国产 | 国产青青操 | 少妇荡乳情欲办公室456视频 | 国产一区视频观看 | 亚洲精品性视频 | 91精品视频免费在线观看 | 狠狠搞av| 欧美深夜在线 | 视频在线日韩 | 91免费高清在线观看 | 精品久久久亚洲 | 国产福利合集 | 国产精品一级片在线观看 | 特黄aaaaaaaaa毛片免 | 国产黄色一级片视频 | 久久黄色小视频 | 激情免费av | 66精品 | 综合激情婷婷 | 亚洲国产电影在线观看 | 国产成人亚洲一区二区 | 精品久久ai | 激情内射人妻1区2区3区 |