Spring Security Oauth2學習(一)

Spring Security Oauth2學習(一)

一、用戶認證需求分析

1.用戶認證和授權

什麼是用戶身份認證?

用戶身份認證就是用戶去訪問系統資源時系統要求驗證用戶的身份信息,身份驗證合法纔可以繼續訪問。
常見的認證方式:用戶賬戶登錄、指紋識別、人臉識別登錄等。

什麼是用戶授權?
用戶認證通過以後去訪問系統資源,系統會判斷用戶是否擁有訪問系統資源的權限,只允許訪問有權限的資源,沒有權限的資源將無法訪問,這個過程叫用戶授權。

2.單點登錄

引用百度百科:單點登錄(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。
SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。
下圖是SSO的示意圖,用戶登錄學成網一次即可訪問多個系統。
在這裏插入圖片描述

3.第三方認證需求

什麼是第三方認證(跨平臺認證)?
當需要訪問第三方系統的資源時需要首先通過第三方系統的認證(例如:微信認證),由第三方系統對用戶認證通過,並授權資源的訪問權限。

在這裏插入圖片描述

二、Oauth2認證

第三方認證技術方案最主要的就是解決認證協議的通用標準問題,因爲要實現跨系統認證,各系統之間要遵循一定的接口協議。

OAUTH協議爲用戶資源授權提供了一個安全的、開發而又簡易的標準。同時,任何第三方都可以使用OAUTH認證服務,任何服務提供商都可以實現自身的OAUTH認證服務,因而OAUTH是開發的。業界提供了OAUTH的多種實現如PHP、JavaScript,Java,Ruby等各種語言開發包,大大節約了程序員的時間,因而OAUTH是簡易的。互聯網很多服務如Open API,很多大公司Google,Yahoo,Microsoft等都提供了OAUTH認證服務,這些都足以說明OAUTH標準逐漸成爲開放資源授權的標準。

參考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth2.0認證流程如下:

引自Oauth2.0協議rfc6749 https://tools.ietf.org/html/rfc6749

在這裏插入圖片描述

Oauth2擁有以下幾個角色:

1.客戶端
本身不存儲資源,需要通過資源擁有者的授權去請求資源服務器的資源,比如:Android客戶端、在線Web客戶端(瀏覽器端)、微信客戶端等。

2.資源擁有者
通常爲用戶,也可以是應用程序,即該資源的擁有者。

3.授權服務器(也稱認證服務器)
用來對資源擁有的身份進行認證、對訪問資源進行授權。客戶端想要訪問資源需要通過認證服務器由資源擁有者授權後方可訪問。

4.資源服務器
存儲資源的服務器,比如用戶管理服務器存儲了用戶信息,微信資源服務器存儲了微信用戶信息,商品管理服務器存儲了商品信息等。客戶端最終訪問資源服務器獲取資源信息。

Oauth2授權模式

Oauth2有以下授權模式:

授權碼模式(Authorization Code) 隱式授權模式(Implicit) 密碼模式(Resource Owner Password
Credentials) 客戶端模式(Client Credentials)

其中授權碼模式和密碼模式應用較多。我主要介紹一下這兩張授權模式。

1.Oauth2授權碼認證過程(主要應用於第三方認證)

下邊分析一個Oauth2認證的例子,黑馬程序員網站使用微信認證的過程:
在這裏插入圖片描述

1.客戶端請求第三方授權
用戶進入黑馬程序的登錄頁面,點擊微信的圖標以微信賬號登錄系統,用戶是自己在微信裏信息的資源擁有者。
在這裏插入圖片描述
點擊“微信”出現一個二維碼,此時用戶掃描二維碼,開始給黑馬程序員授權。
在這裏插入圖片描述
2、資源擁有者同意給客戶端授權

資源擁有者掃描二維碼錶示資源擁有者同意給客戶端授權,微信會對資源擁有者的身份進行驗證, 驗證通過後,微信會詢問用戶是否給授權黑馬程序員訪問自己的微信數據,用戶點擊“確認登錄”表示同意授權,微信認證服務器會頒發一個授權碼,並重定向到黑馬程序員的網站。
在這裏插入圖片描述
3、客戶端獲取到授權碼,請求認證服務器申請令牌

此過程用戶看不到,客戶端應用程序請求認證服務器,請求攜帶授權碼。

4、認證服務器向客戶端響應令牌

認證服務器驗證了客戶端請求的授權碼,如果合法則給客戶端頒發令牌,令牌是客戶端訪問資源的通行證。

此交互過程用戶看不到,當客戶端拿到令牌後,用戶在黑馬程序員看到已經登錄成功。
5、客戶端請求資源服務器的資源

客戶端攜帶令牌訪問資源服務器的資源。

黑馬程序員網站攜帶令牌請求訪問微信服務器獲取用戶的基本信息。

6、資源服務器返回受保護資源

資源服務器校驗令牌的合法性,如果合法則向用戶響應資源信息內容。

注意:資源服務器和認證服務器可以是一個服務也可以分開的服務,如果是分開的服務資源服務器通常要請求認證服務器來校驗令牌的合法性。

上邊例舉的黑馬程序員網站使用微信認證的過程就是授權碼模式,流程如下:

1、客戶端請求第三方認證 2、用戶(資源擁有者同意給客戶端授權)3、客戶端獲取授權碼,請求認證服務器申請令牌 4、認證服務器向客戶端響應令牌 5、客戶端請求資源服務器的資源,資源服務效驗令牌合法性,完成授權 6、資源服務器返回受保護資源

申請授權碼

請求認證服務獲取授權碼:
Get請求:

localhost:40400/auth/oauth/authorize?
client_id=XcWebApp&response_type=code&scop=app&redirect_uri=http://localhost

參數列表如下:

client_id:客戶端id,和授權配置類中設置的客戶端id一致。
response_type:授權碼模式固定爲code
scop:客戶端範圍,和授權配置類中設置的scop一致。
redirect_uri:跳轉uri,當授權碼申請成功後會跳轉到此地址,並在後邊帶上code參數(授權碼)。

首先跳轉到登錄頁面:
在這裏插入圖片描述
輸入賬號密碼,點擊登錄。

Spring Security接收到請求會調用UserDetailsService接口的loadUserByUsername方法查詢用戶正確的密碼。

賬號密碼驗證通過,接下來進入授權頁面:
在這裏插入圖片描述
點擊“同意”。
接下來返回授權碼:
認證服務攜帶授權碼跳轉redirect_uri

在這裏插入圖片描述

申請令牌

拿到授權碼後,申請令牌。
Post請求:

http://localhost:40400/auth/oauth/token

參數如下:
grant_type:授權類型,填寫authorization_code,表示授權碼模式
code:授權碼,就是剛剛獲取的授權碼,注意:授權碼只使用一次就無效了,需要重新申請。
redirect_uri:申請授權碼時的跳轉url,一定和申請授權碼時用的redirect_uri一致。
此鏈接需要使用 http Basic認證。

什麼是http Basic認證?

http協議定義的一種認證方式,將客戶端id和客戶端密碼按照“客戶端ID:客戶端密碼”的格式拼接,並用base64編
碼,放在header中請求服務端,一個例子:

Authorization: Basic WGNXZWJBcHA6WGNXZWJBcHA=

WGNXZWJBcHA6WGNXZWJBcHA= 是用戶名:密碼的base64編碼。

認證失敗服務端返回 401 Unauthorized

以上測試使用postman完成:
http basic認證:
在這裏插入圖片描述
右邊的賬號密碼:是spring Security自帶的表 oauth_client_details表裏存的,後面細講該表。

客戶端Id和客戶端密碼會匹配數據庫oauth_client_details表中的客戶端id及客戶端密碼。

Post請求參數:點擊Body,填寫參數
在這裏插入圖片描述
點擊發送:
申請令牌成功:
在這裏插入圖片描述
access_token:訪問令牌,攜帶此令牌訪問資源

token_type:有MAC Token與Bearer Token兩種類型,兩種的校驗算法不同,RFC 6750建議Oauth2採用 Bearer Token(http://www.rfcreader.com/#rfc6750)。

refresh_token:刷新令牌,使用此令牌可以延長訪問令牌的過期時間。

expires_in:過期時間,單位爲秒。

scope:範圍,與定義的客戶端範圍一致。

2. Oauth2密碼模式授權

密碼模式(Resource Owner Password Credentials)與授權碼模式的區別是申請令牌不再使用授權碼,而是直接通過用戶名和密碼即可申請令牌。

測試如下:
Post請求:

http://localhost:40400/auth/oauth/token

參數:
grant_type:密碼模式授權填寫password
username:賬號
password:密碼
並且此鏈接需要使用 http Basic認證。
在這裏插入圖片描述
上邊參數使用x-www-form-urlencoded方式傳輸,使用postman測試如下:
在這裏插入圖片描述
注意:當令牌沒有過期時同一個用戶再次申請令牌則不再頒發新令牌。

校驗令牌

Spring Security Oauth2提供校驗令牌的端點,如下:
Get:

 http://localhost:40400/auth/oauth/check_token?token=

參數:
token:令牌
使用postman測試如下:
在這裏插入圖片描述
結果如下:

{
"companyId": null,
"userpic": null,
"user_name": "mrt",
"scope": [
"app"
],
"name": null,
"utype": null,
"id": null,
"exp": 1531254828,
"jti": "6a00f227‐4c30‐47dc‐a959‐c0c147806462",
"client_id": "XcWebApp"
}

exp:過期時間,long類型,距離1970年的秒數(new Date().getTime()可得到當前時間距離1970年的毫秒數)。
user_name: 用戶名
client_id:客戶端Id,在oauth_client_details中配置
scope:客戶端範圍,在oauth_client_details表中配置
jti:與令牌對應的唯一標識
companyId、userpic、name、utype、id:這些字段是本認證服務在Spring Security基礎上擴展的用戶身份信息

刷新令牌

刷新令牌是當令牌快過期時重新生成一個令牌,它於授權碼授權和密碼授權生成令牌不同,刷新令牌不需要授權碼也不需要賬號和密碼,只需要一個刷新令牌、客戶端id和客戶端密碼。
測試如下:
Post請求:

http://localhost:40400/auth/oauth/token

參數:
grant_type: 固定爲 refresh_token
refresh_token:刷新令牌(注意不是access_token,而是refresh_token)

在這裏插入圖片描述
刷新令牌成功,會重新生成新的訪問令牌和刷新令牌,令牌的有效期也比舊令牌長。
刷新令牌通常是在令牌快過期時進行刷新。

3.資源服務授權

前面兩節都是獲取令牌的主要流程和相關請求過程。資源服務擁有要訪問的受保護資源,客戶端獲取令牌以後會攜帶令牌去訪問資源,如下圖:
在這裏插入圖片描述
上圖的業務流程如下:
1、客戶端請求認證服務申請令牌
2、認證服務生成令牌
認證服務採用非對稱加密算法,使用私鑰生成令牌。
3、客戶端攜帶令牌訪問資源服務
客戶端在Http header 中添加: Authorization:Bearer 令牌。
4、資源服務請求認證服務校驗令牌的有效性
資源服務接收到令牌,使用公鑰校驗令牌的合法性。
5、令牌有效,資源服務向客戶端響應資源信息

資源服務授權配置

基本上所有微服務都是資源服務,這裏我們在課程管理服務上配置授權控制,當配置了授權控制後如要訪問課程信息則必須提供令牌。

1.配置公鑰
認證服務生成令牌採用非對稱加密算法,認證服務採用私鑰加密生成令牌,對外向資源服務提供公鑰,資源服務使用公鑰 來校驗令牌的合法性。
將公鑰拷貝到 publickey.txt文件中,將此文件拷貝到資源服務工程的classpath下
在這裏插入圖片描述
2、添加依賴

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring‐cloud‐starter‐oauth2</artifactId>
</dependency>

3.創建ResourceServerConfig類:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize註解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
//公鑰
private static final String PUBLIC_KEY = "publickey.txt";

//定義JwtTokenStore,使用jwt令牌
@Bean
public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
	return new JwtTokenStore(jwtAccessTokenConverter);
}

//定義JJwtAccessTokenConverter,使用jwt令牌
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
	JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
	converter.setVerifierKey(getPubKey());
	return converter;
}

/**
* 獲取非對稱加密公鑰 Key
* @return 公鑰 Key
*/
private String getPubKey() {
	Resource resource = new ClassPathResource(PUBLIC_KEY);
	try {
		InputStreamReader inputStreamReader = new
		InputStreamReader(resource.getInputStream());
		BufferedReader br = new BufferedReader(inputStreamReader);
		return br.lines().collect(Collectors.joining("\n"));
	} catch (IOException ioe) {
	return null;
	}
}

//Http安全配置,對每個到達系統的http請求鏈接進行校驗
@Override
public void configure(HttpSecurity http) throws Exception {
	//所有請求必須認證通過
	http.authorizeRequests().anyRequest().authenticated();
	}
}

資源服務授權測試

以查詢獲取圖片爲例:
get

http://localhost:31200/course/coursepic/list/4028e58161bd3b380161bd3bcd2f0000

請求時沒有攜帶令牌則報錯:

{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}

請求時攜帶令牌:
在http header中添加 Authorization: Bearer 令牌
在這裏插入圖片描述
當輸入錯誤的令牌也無法正常訪問資源。
在這裏插入圖片描述

4.Oauth2相關表

在這裏插入圖片描述
以“oauth_”開頭的表都是spring Security 自帶的表
本項目中spring Security 主要使用oauth_client_details表:在這裏插入圖片描述
client_id:客戶端id
resource_ids:資源id(暫時不用)
client_secret:客戶端密碼
scope:範圍
access_token_validity:訪問token的有效期(秒)
refresh_token_validity:刷新token的有效期(秒)
authorized_grant_type:授權類型,authorization_code,password,refresh_token,client_credentials

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章