OAuth2

http://www.itdecent.cn/p/68f22f9a00ee

鏈接: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)站,這樣存在很大的安全問題:

  1. 提供賬號(hào)和密碼給第三方應(yīng)用程序后,應(yīng)用可以訪問用戶在微信上的所有數(shù)據(jù)(有什么群,好友)。
  2. 用戶只有修改密碼后,才可以收回權(quán)限。但是如果一樣將用戶名和密碼授權(quán)給了其他第三方應(yīng)用,當(dāng)你修改密碼后,那么所有第三方應(yīng)用程序都會(huì)被收回權(quán)限。
  3. 密碼泄露的可能性大大提高。因?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)碼模式流程
image.png
簡化模式流程
image.png
密碼模式流程
  1. 用戶向客戶端直接提供認(rèn)證服務(wù)器平臺(tái)的用戶名和密碼。
  2. 客戶端將用戶名和密碼發(fā)給認(rèn)證服務(wù)器,向后者請(qǐng)求令牌。
  3. 認(rèn)證服務(wù)器確認(rèn)無誤后,向客戶端提供訪問令牌。
客戶端模式流程
  1. 客戶端向認(rèn)證服務(wù)器進(jìn)行身份認(rèn)證,并要求一個(gè)訪問令牌。
  2. 認(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ǔ)就不太合適,原因:

  1. 開發(fā)復(fù)雜
  2. 安全性差
  3. 客戶體驗(yàn)差
  4. 有些前端技術(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ù)器配置類

作用:

  1. 配置被允許訪問此認(rèn)證服務(wù)器的客戶端信息, 沒有在此配置的客戶端是不允許訪問的
  2. 管理令牌:
  • 配置令牌管理策略(如:JDBC/ Redis/JWT)
  • 配置令牌生成策略
  • 配置令牌端點(diǎn)
  • 令牌端點(diǎn)的安全配置

步驟:

  1. 創(chuàng)建 AuthorizationServerConfig 類繼承AuthorizationServerConfigurerAdapter
  2. 在類上添加注解:
    @Configuration 標(biāo)識(shí)配置類
    @EnableAuthorizationServer 開啟 OAuth2 認(rèn)證服務(wù)器功能,
  3. 配置說明:
    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)的用戶,即資源所有者。
步驟

  1. 創(chuàng)建SpringSecurityConfig 類繼承WebSecurityConfigurerAdapter
  2. 在類上添加注解:@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)碼
  1. 請(qǐng)求如下地址申請(qǐng)授權(quán)碼(注意:路徑加上下文路徑 /auth )
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code
  1. 當(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
  1. 輸入用戶名密碼后,登錄后會(huì)重新跳轉(zhuǎn)授權(quán)頁面,詢問資源所有者:是否將受保護(hù)的資源授權(quán)給 mengxuegu?pc 客戶端:


    image.png
  2. 選擇 Approve 后,點(diǎn)擊 authorize 同意授權(quán) scope.all 資源后,會(huì)跳轉(zhuǎn)到指定的 redirect_uri ,回調(diào)路徑攜
    帶了帶著一個(gè)授權(quán)碼( code=V3ENnC ) ,如下圖:


    image.png
  3. 獲取到授權(quán)碼(code) 后,就可以通過它來獲取訪問令牌(access_token)。

通過授權(quán)碼獲取令牌 token
POST 方式請(qǐng)求:http://localhost:8090/auth/oauth/token
  1. 請(qǐng)求頭: Authorization: Basic bWVuZ3h1ZWd1LXBjOm1lbmd4dWVndS1zZWNyZXQ=
    是將 client_id:client_secret 通過 Base64 編碼


    image.png
  2. post 方式,請(qǐng)求體中指定 授權(quán)方式 和 授權(quán)碼


    image.png
  3. 每個(gè)授權(quán)碼申請(qǐng)令牌后就會(huì)失效了,需要重新發(fā)送請(qǐng)求獲取授權(quán)碼再去認(rèn)證, 如下再請(qǐng)求就失敗了


    image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容