鏈接:https://pan.baidu.com/s/1pG9Puiak88oYeTAtrg5AuA
提取碼:embi
OAuth2 是什么
OAuth 2.0 是目前最流行的授權(quán)機(jī)制,用來授權(quán)第三方應(yīng)用,獲取用戶數(shù)據(jù)。
OAuth 協(xié)議為用戶資源的授權(quán)提供了一個(gè)安全的、開放而又簡易的規(guī)范標(biāo)準(zhǔn)。與以往的授權(quán)方式不同之處是
OAuth 的授權(quán)不會(huì)使第三方觸及到用戶的帳號(hào)信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與密碼就可以申請(qǐng)獲得該用戶資源的授權(quán),因此 OAuth 是開放的安全的。
業(yè)界提供了 OAuth 的多種實(shí)現(xiàn),如 Java、PHP、Ruby 等各種語言開發(fā)包,大大節(jié)約了程序員的時(shí)間,因而OAuth是簡易的。很多大公司如 阿里、騰訊、 Google,Yahoo,Microsoft等都提供了 OAuth 認(rèn)證服務(wù),這些都足以說明 OAuth 標(biāo)準(zhǔn)逐漸成為開放資源授權(quán)的標(biāo)準(zhǔn)。
OAuth 協(xié)議1.0版本過于復(fù)雜,目前發(fā)展到2.0版本,2.0版本已得到廣泛應(yīng)用。
OAuth 2.0參考:https://oauth.net/2/
中文版參考:https://github.com/jeansfish/RFC6749.zh-cn/blob/master/SUMMARY.md
OAuth2 要解決的問題
比如:進(jìn)入某網(wǎng)站時(shí),不想注冊(cè)帳號(hào),而是希望通過微信進(jìn)行登錄。
如果微信用戶同意提供帳號(hào)和密碼去獲取微信信息,進(jìn)行登錄網(wǎng)站,這樣存在很大的安全問題:
- 提供賬號(hào)和密碼給第三方應(yīng)用程序后,應(yīng)用可以訪問用戶在微信上的所有數(shù)據(jù)(有什么群,好友)。
- 用戶只有修改密碼后,才可以收回權(quán)限。但是如果一樣將用戶名和密碼授權(quán)給了其他第三方應(yīng)用,當(dāng)你修改密碼后,那么所有第三方應(yīng)用程序都會(huì)被收回權(quán)限。
- 密碼泄露的可能性大大提高。因?yàn)闊o法控制接入應(yīng)用對(duì)用戶數(shù)據(jù)保護(hù)的安全系數(shù),只要有一個(gè)接入的第三方應(yīng)用遭到破解,那么用戶的密碼就會(huì)泄露,意味著用戶的信息全部會(huì)被泄露,后果不堪設(shè)想。
OAuth 就是為了解決上面這些問題而誕生的。OAuth 協(xié)議規(guī)范了授權(quán)方式,不采用授權(quán)帳號(hào)和密碼的方式,而是使用令牌方式(Token)來解決授權(quán)問題,應(yīng)用通過令牌去獲取被授權(quán)的用戶信息,從而可以避免上面存在的安全問題。
OAuth2 涉及的角色
-
資源所有者(Resource Owner): 通常為 "用戶"(user),如昵稱、頭像等這些資源的擁有者(用戶只是
將這些資源放到了服務(wù)提供商的資源服務(wù)器中)。 -
第三方應(yīng)用(Third-party application): 又稱為客戶端(Client),比如 夢(mèng)學(xué)谷官網(wǎng)想要使用微信的資源
(昵稱、頭像等),夢(mèng)學(xué)谷官網(wǎng)對(duì)于QQ、微信等系統(tǒng)來說是第三者,我們稱夢(mèng)學(xué)谷官網(wǎng)為第三方應(yīng)用。 - **認(rèn)證服務(wù)器(Authorization server): **專門用來對(duì)資源所有者的身份進(jìn)行認(rèn)證、對(duì)要訪問的資源進(jìn)行授
權(quán)、產(chǎn)生令牌的服務(wù)器。想訪問資源,需要通過認(rèn)證服務(wù)器由資源所有者授權(quán)后才可訪問。 -
資源服務(wù)器(Resource server): 存儲(chǔ)用戶的資源(昵稱、頭像等)、驗(yàn)證令牌有效性。比如: 微信的資源
服務(wù)器存儲(chǔ)了微信的用戶信息,淘寶的資源服務(wù)器存儲(chǔ)了淘寶的用戶信息等。
注意:認(rèn)證服務(wù)器 和資源服務(wù)器 雖然是兩個(gè)解決,但其實(shí)他們可以是同一臺(tái)服務(wù)器、同一個(gè)應(yīng)用。 - 服務(wù)提供商(Service Provider): 如 QQ、微信等 (包含認(rèn)證和資源服務(wù)器)。
OAuth2 認(rèn)證流程
OAuth 在 "第三方應(yīng)用" 與 "服務(wù)提供商" 之間,設(shè)置了一個(gè)授權(quán)層(authorization layer)。"第三方應(yīng)用" 不能直接登錄 "服務(wù)提供商",只能通過授權(quán)層將 "第三方應(yīng)用" 與用戶區(qū)分開來。"第三方應(yīng)用" 通過授權(quán)層獲取令牌(token), 獲取令牌后拿令牌去訪問服務(wù)提供商。令牌和用戶的密碼不同,可以指定授權(quán)層令牌的權(quán)限范圍和有效期,"服務(wù)提供商" 根據(jù)令牌的權(quán)限范圍和有效期,向 "第三方應(yīng)用" 開放用戶對(duì)應(yīng)的資源。
OAuth2 協(xié)議的授權(quán)模式
- 授權(quán)碼模式(Authorization Code):功能最完整,流程最嚴(yán)密的授權(quán)模式。國內(nèi)各大服務(wù)提供商(微信、QQ、微博、淘寶、百度)都采用此模式進(jìn)行授權(quán)??梢源_定是用戶真正同意授權(quán);而且令牌是認(rèn)證服務(wù)器發(fā)放給第三方應(yīng)用的服務(wù)器,而不是瀏覽器上。
- 簡化模式(Implicit):令牌是發(fā)放給瀏覽器的,oauth客戶端運(yùn)行在瀏覽器中,通過JS腳本去申請(qǐng)令牌。而不是發(fā)放給第三方應(yīng)用的服務(wù)器。
- 密碼模式(Resource Owner Password Credentials):將用戶名和密碼傳過去,直接獲取 access_token 。用戶同意授權(quán)動(dòng)作是在第三方應(yīng)用上完成,而不是在認(rèn)證服務(wù)器上。第三方應(yīng)用申請(qǐng)令牌時(shí),直接帶著用戶名密碼去向認(rèn)證服務(wù)器申請(qǐng)令牌。這種方式認(rèn)證服務(wù)器無法斷定用戶是否真的授權(quán)了,用戶名密碼可能是第三方應(yīng)用盜取來的。
- 客戶端證書模式(Client credentials):用得少。當(dāng)一個(gè)第三應(yīng)用自己本身需要獲取資源(而不是以用戶的名義),而不是獲取用戶的資源時(shí),客戶端模式十分有用。
授權(quán)碼模式流程

簡化模式流程

密碼模式流程
- 用戶向客戶端直接提供認(rèn)證服務(wù)器平臺(tái)的用戶名和密碼。
- 客戶端將用戶名和密碼發(fā)給認(rèn)證服務(wù)器,向后者請(qǐng)求令牌。
- 認(rèn)證服務(wù)器確認(rèn)無誤后,向客戶端提供訪問令牌。
客戶端模式流程
- 客戶端向認(rèn)證服務(wù)器進(jìn)行身份認(rèn)證,并要求一個(gè)訪問令牌。
-
認(rèn)證服務(wù)器確認(rèn)無誤后,向客戶端提供訪問令牌。
image.png
Spring Security OAuth2 認(rèn)證服務(wù)器
概述
Spring Seucrity 登錄信息存在Session中,每次訪問服務(wù)時(shí),會(huì)去查看瀏覽器中的 Cookie 中是否存在JSESSIONID,如果不存在會(huì)新建一個(gè)Session, 將新建的SessionID 保存到Cookie 中。每次發(fā)請(qǐng)求會(huì)通過瀏覽器的SessionID查找到對(duì)應(yīng)的Session對(duì)象,從而獲取用戶信息。
前后端分離,前端部署在單獨(dú)Web服務(wù)器,后臺(tái)部署在另外一臺(tái)應(yīng)用服務(wù)器,瀏覽器先訪問Web服務(wù)器,Web服務(wù)器再發(fā)送請(qǐng)求到應(yīng)用服務(wù)器中。這樣采用Cookie存儲(chǔ)就不太合適,原因:
- 開發(fā)復(fù)雜
- 安全性差
- 客戶體驗(yàn)差
- 有些前端技術(shù) 不支持Cookie, 如:小程序
解決:
采用令牌方式進(jìn)行認(rèn)證就可以上面的問題,就可以使用 OAuth2 協(xié)議標(biāo)準(zhǔn)中的實(shí)現(xiàn) Spring Security OAuth2 解決。
添加依賴
<!-- Spring Security、OAuth2 和JWT等 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
配置 application.yml
注意:配置了項(xiàng)目的上下文路徑 /auth ,請(qǐng)求時(shí)要加上,即 http://localhost:8090/auth 作為請(qǐng)求前綴
server
port: 8090
servlet:
context-path: /auth # 上下文路徑,請(qǐng)求時(shí)要加上,后面網(wǎng)關(guān)時(shí)有用
配置認(rèn)證服務(wù)器-授權(quán)碼模式
創(chuàng)建認(rèn)證服務(wù)器配置類
作用:
- 配置被允許訪問此認(rèn)證服務(wù)器的客戶端信息, 沒有在此配置的客戶端是不允許訪問的
- 管理令牌:
- 配置令牌管理策略(如:JDBC/ Redis/JWT)
- 配置令牌生成策略
- 配置令牌端點(diǎn)
- 令牌端點(diǎn)的安全配置
步驟:
- 創(chuàng)建 AuthorizationServerConfig 類繼承AuthorizationServerConfigurerAdapter
- 在類上添加注解:
@Configuration 標(biāo)識(shí)配置類
@EnableAuthorizationServer 開啟 OAuth2 認(rèn)證服務(wù)器功能, - 配置說明:
withClient:允許訪問此認(rèn)證服務(wù)器的客戶端id , 如:PC、APP、小程序各不同的的客戶端id。
secret:客戶端密碼,要加密存儲(chǔ),不然獲取不到令牌一直要求登錄,, 而且一定不能被泄露。
authorizedGrantTypes: 授權(quán)類型, 可同時(shí)支持多種授權(quán)類型:
可配置:"authorization_code", "password", "implicit","client_credentials","refresh_token"
scopes:授權(quán)范圍標(biāo)識(shí),如指定微服務(wù)名稱,則只能訪問指定的微服務(wù)。
autoApprove:false 跳轉(zhuǎn)到授權(quán)頁面手動(dòng)點(diǎn)擊授權(quán),true 不用手動(dòng)授權(quán),直接響應(yīng)授權(quán)碼。
@Configuration
@EnableAuthorizationServer // 開啟了認(rèn)證服務(wù)器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private DataSource dataSource;
@Bean
public ClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
/**
* 配置被允許訪問此認(rèn)證服務(wù)器的客戶端信息
* 1.內(nèi)存方式
* 2.數(shù)據(jù)庫方式
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 內(nèi)存方式管理客戶端信息
clients.inMemory()
.withClient("mengxuegu-pc") // 客戶端id
.secret(passwordEncoder.encode("mengxuegu-secret")) // 客戶端密碼(加密)
.resourceIds("product-server") // 資源id,針對(duì)的是微服務(wù)名稱(如商品管理)。沒有配置默認(rèn)每個(gè)微服務(wù)都能訪問
/**
* 授權(quán)碼模式(Authorization Code):【常用】
* 簡化模式(Implicit): 【無后臺(tái)應(yīng)用】
* 密碼模式(Resource Owner Password Credentials):【公司內(nèi)部搭建認(rèn)證服務(wù)器】
* 客戶端證書模式(Client credentials):【微服務(wù)之間調(diào)用】
* 刷新臨牌【過期自動(dòng)重新刷新獲取】
*/
.authorizedGrantTypes("authorization_code", "password", "implicit", "client_credentials", "refresh_token")//指定多種類型,客戶端就能通過多種類型訪問
.scopes("all") // 授權(quán)范圍標(biāo)識(shí),哪部分資源可訪問(all只是標(biāo)識(shí),不是說所有資源)【具體資源如修改/查看】
.autoApprove(false) // false 跳到一個(gè)授權(quán)頁面手動(dòng)點(diǎn)擊授權(quán),true不需要手動(dòng)點(diǎn)授權(quán),直接響應(yīng)一個(gè)授權(quán)碼
.redirectUris("http://www.mengxuegu.com/")// 客戶端回調(diào)地址【認(rèn)證服務(wù)器響應(yīng)授權(quán)碼后,客戶端將授權(quán)碼附著在這個(gè)回調(diào)地址后面,進(jìn)行請(qǐng)求 申請(qǐng)令牌】
.accessTokenValiditySeconds(60*60*8) //訪問令牌有效時(shí)長 默認(rèn)為12小時(shí)
.refreshTokenValiditySeconds(60*60*24*60) // 刷新令牌有效時(shí)長,默認(rèn)是30天
;
}
創(chuàng)建安全配置類
概要
指定要進(jìn)行認(rèn)證用戶的用戶名和密碼,這個(gè)用戶名和密碼是資源所有者的。
和上面指定的客戶端id和密碼是不一樣的,客戶端的id和密碼是應(yīng)用系統(tǒng)的標(biāo)識(shí),每個(gè)應(yīng)用系統(tǒng)就對(duì)應(yīng)一個(gè)客戶端ip和密碼。
而這里指定的用戶名和密碼是客戶的,就是每個(gè)應(yīng)用系統(tǒng)的用戶,即資源所有者。
步驟
- 創(chuàng)建SpringSecurityConfig 類繼承WebSecurityConfigurerAdapter
- 在類上添加注解:@EnableWebSecurity , 它包含了 @Configuration 注解所以不用加
/**
* 安全配置類
* springSecurity的身份認(rèn)證
*/
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserDetailsService customUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//比如簡單的內(nèi)存認(rèn)證 賬號(hào)密碼
// auth.inMemoryAuthentication()
// .withUser("admin").password(passwordEncoder.encode("1234"))
// .authorities("product");
//不使用內(nèi)存方式,就自定義CustomUserDetailsService【數(shù)據(jù)庫查對(duì)應(yīng)用戶名密碼匹配驗(yàn)證】,然后這里作為參數(shù)傳入認(rèn)證。
auth.userDetailsService(customUserDetailsService);
}
}
運(yùn)行認(rèn)證服務(wù)器
令牌訪問端點(diǎn)
Spring Security 對(duì) OAuth2 默認(rèn)提供了可直接訪問端點(diǎn),即URL:
- /oauth/authorize :申請(qǐng)授權(quán)碼 code, 涉及的類 AuthorizationEndpoint
- /oauth/token :/獲取令牌 token, 涉及的類 TokenEndpoint
- /oauth/check_token :用于資源服務(wù)器請(qǐng)求端點(diǎn)來檢查令牌是否有效, 涉及的類 CheckTokenEndpoint
- /oauth/confirm_access :用戶確認(rèn)授權(quán)提交, 涉及的類 WhitelabelApprovalEndpoint
- /oauth/error :授權(quán)服務(wù)錯(cuò)誤信息, 涉及的類 WhitelabelErrorEndpoint
- /oauth/token_key :提供公有密匙的端點(diǎn),使用 JWT 令牌時(shí)會(huì)使用 , 涉及的類 TokenKeyEndpoint
發(fā)送請(qǐng)求獲取授權(quán)碼
- 請(qǐng)求如下地址申請(qǐng)授權(quán)碼(注意:路徑加上下文路徑 /auth )
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code
- 當(dāng)請(qǐng)求到達(dá)授權(quán)中心的
AuthorizationEndpoint后,授權(quán)中心將會(huì)要求資源所有者做身份驗(yàn)證
注意:
- 此處輸入的用戶名、密碼是在認(rèn)證服務(wù)器輸入的(看端口8090),而不是在客戶端上輸入的,這樣更加
安全,因?yàn)榭蛻舳瞬恢烙脩舻挠脩裘兔艽a。 -
而密碼模式中,輸入的用戶名、密碼不是在認(rèn)證服務(wù)器(不是8090端口)上輸入的,而是在客戶端(第
三方應(yīng)用)輸入的,這樣客戶端知識(shí)了就不太安全。
image.png
-
輸入用戶名密碼后,登錄后會(huì)重新跳轉(zhuǎn)授權(quán)頁面,詢問資源所有者:是否將受保護(hù)的資源授權(quán)給 mengxuegu?pc 客戶端:
image.png -
選擇 Approve 后,點(diǎn)擊 authorize 同意授權(quán) scope.all 資源后,會(huì)跳轉(zhuǎn)到指定的 redirect_uri ,回調(diào)路徑攜
帶了帶著一個(gè)授權(quán)碼( code=V3ENnC ) ,如下圖:
image.png 獲取到授權(quán)碼(code) 后,就可以通過它來獲取訪問令牌(access_token)。
通過授權(quán)碼獲取令牌 token
POST 方式請(qǐng)求:http://localhost:8090/auth/oauth/token
-
請(qǐng)求頭: Authorization: Basic bWVuZ3h1ZWd1LXBjOm1lbmd4dWVndS1zZWNyZXQ=
是將 client_id:client_secret 通過 Base64 編碼
image.png -
post 方式,請(qǐng)求體中指定 授權(quán)方式 和 授權(quán)碼
image.png -
每個(gè)授權(quán)碼申請(qǐng)令牌后就會(huì)失效了,需要重新發(fā)送請(qǐng)求獲取授權(quán)碼再去認(rèn)證, 如下再請(qǐng)求就失敗了
image.png






