久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

可能是第二好的 Spring OAuth 2.0 文章,,艿艿端午在家寫了 3 天~

 壞尐孒95qanplv 2020-07-04

管她前浪,還是后浪,?

能浪的浪,,才是好浪!

每天 8:55 更新文章,,每天掉億點點頭發(fā)...

源碼精品專欄

 

摘要: 原創(chuàng)出處 http://www./Spring-Security/OAuth2-learning/ 「芋道源碼」歡迎轉(zhuǎn)載,保留摘要,,謝謝,!

  • 1. 概述
  • 2. 密碼模式
  • 3. 授權(quán)碼模式
  • 4. 簡化模式
  • 5. 客戶端模式
  • 6. 合并服務(wù)器
  • 7. 刷新令牌
  • 8. 刪除令牌
  • 666. 彩蛋

本文在提供完整代碼示例,可見 https://github.com/YunaiV/SpringBoot-Labs 的 lab-68-spring-security-oauth 目錄,。

原創(chuàng)不易,,給點個 Star 嘿,一起沖鴨,!

1. 概述

在《芋道 Spring Boot 安全框架 Spring Security 入門》文章中,,艿艿分享了如何使用 Spring Security 實現(xiàn)認(rèn)證與授權(quán)的功能,獲得廣大女粉絲的好評,。

于是乎,,艿艿準(zhǔn)備再來分享一波 Spring Security OAuth 框架,看看在 Spring Security 如何實現(xiàn) OAuth2.0 實現(xiàn)授權(quán)的功能,。

旁白君:實際上艿艿很早寫了一篇關(guān)于 Spring Security OAuth 的文章,,考慮到版本太老,,提供的示例又過于簡單,所以本文也是該文章的升級版,。

可能有胖友對 OAuth2.0 不是很了解,,所以我們先來簡單介紹下它??赡芘钟芽?OAuth2.0 的概念會有點懵逼,,不要擔(dān)心,后續(xù)看完艿艿提供的示例代碼,,會突然清晰的哈,。

另外,阮一峰提供了幾篇關(guān)于 OAuth2.0 非常不錯的文章,,推薦胖友去從瞅瞅,。同時,本文也會直接引用它的內(nèi)容,,方便胖友統(tǒng)一理解,。

  • 《理解 OAuth2.0》
  • 《OAuth2.0 的一個簡單解釋》
  • 《OAuth2.0 的四種方式》
  • 《GitHub OAuth 第三方登錄示例教程》

1.1 OAuth2.0 是什么?

FROM 《維基百科 —— 開放授權(quán)》

OAuth(Open Authorization)是一個開放標(biāo)準(zhǔn),,允許用戶讓第三方應(yīng)用訪問該用戶在某一網(wǎng)站上存儲的私密的資源(如照片,,視頻,聯(lián)系人列表),,而無需將用戶名和密碼提供給第三方應(yīng)用,。

旁白君:很多團隊,內(nèi)部會采用 OAuth2.0 實現(xiàn)一個授權(quán)服務(wù),,避免每個上層應(yīng)用或者服務(wù)重復(fù)開發(fā),。

OAuth 允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務(wù)提供者的數(shù)據(jù),。

每一個令牌授權(quán)一個特定的網(wǎng)站(例如,視頻編輯網(wǎng)站)在特定的時段(例如,,接下來的 2 小時內(nèi))內(nèi)訪問特定的資源(例如僅僅是某一相冊中的視頻),。這樣,OAuth 讓用戶可以授權(quán)第三方網(wǎng)站訪問他們存儲在另外服務(wù)提供者的某些特定信息,,而非所有內(nèi)容,。

旁白君:如果胖友對接過微信網(wǎng)頁授權(quán)功能,就會發(fā)現(xiàn)分成兩種方式:靜默授權(quán),、手動授權(quán),。前者只能獲取到用戶的 openid,而后者可以獲取到用戶的基本信息,。

OAuth2.0 是用于授權(quán)的行業(yè)標(biāo)準(zhǔn)協(xié)議,。OAuth2.0 為簡化客戶端開發(fā)提供了特定的授權(quán)流,,包括 Web 應(yīng)用、桌面應(yīng)用,、移動端應(yīng)用等,。

旁白君:OAuth 1.0 協(xié)議體系本身存在一些問題,現(xiàn)已被各大開發(fā)平臺逐漸廢棄,。

1.2 OAuth2.0 角色解釋

在 OAuth2.0 中,,有如下角色:

Authorization Server:認(rèn)證服務(wù)器,用于認(rèn)證用戶,。如果客戶端認(rèn)證通過,,則發(fā)放訪問資源服務(wù)器的令牌

Resource Server:資源服務(wù)器,,擁有受保護資源,。如果請求包含正確的訪問令牌,則可以訪問資源,。

友情提示:提供管理后臺,、客戶端 API 的服務(wù),都可以認(rèn)為是 Resource Server,。

Client:客戶端,。它請求資源服務(wù)器時,會帶上訪問令牌,,從而成功訪問資源,。

友情提示:Client 可以是瀏覽器、客戶端,,也可以是內(nèi)部服務(wù),。

④ Resource Owner:資源擁有者。最終用戶,,他有訪問資源的賬號密碼,。

友情提示:可以簡單把 Resource Owner 理解成人,她在使用 Client 訪問資源,。

1.3 OAuth 2.0 運行流程

如下是 OAuth 2.0 的授權(quán)碼模式的運行流程:

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

上述的六個步驟,B 是關(guān)鍵,,即用戶如何給客戶端進行授權(quán)。有了授權(quán)之,,客戶端就可以獲取令牌,,進而憑令牌獲取資源

友情提示:如果胖友有對接過三方開放平臺,,例如說微信、QQ,、微博等三方登錄,,就會很容易理解這個步驟過程。

這個時候的資源,,資源主要指的是三方開放平臺的用戶資料等等,。

1.4 OAuth 2.0 授權(quán)模式

客戶端必須得到用戶的授權(quán)(Authorization Grant),才能獲得訪問令牌(Access Token),。

OAuth2.0 定義了四種授權(quán)方式:

  • 授權(quán)碼模式(Authorization Code)
  • 密碼模式(Resource Owner Password Credentials)
  • 簡化模式(Implicit)
  • 客戶端模式(Client Credentials)

其中,,密碼模式授權(quán)碼模式比較常用。至于如何選擇,,艿艿這里先提前劇透下,,后續(xù)慢慢細(xì)品。

FROM 《深度剖析 OAuth2 和微服務(wù)安全架構(gòu)》

授權(quán)類型選擇

當(dāng)然,,對于黃框部分,,對于筆者還是比較困惑的。筆者認(rèn)為,,第三方的單頁應(yīng)用 SPA ,也是適合采用 Authorization Code Grant 授權(quán)模式的,。例如,,《微信網(wǎng)頁授權(quán)》 :

具體而言,網(wǎng)頁授權(quán)流程分為四步:

  • 1,、引導(dǎo)用戶進入授權(quán)頁面同意授權(quán),,獲取 code
  • 2,、通過 code 換取網(wǎng)頁授權(quán) access_token(與基礎(chǔ)支持中的 access_toke n不同)
  • 3、如果需要,,開發(fā)者可以刷新網(wǎng)頁授權(quán) access_token,,避免過期
  • 4、通過網(wǎng)頁授權(quán) access_token 和 openid 獲取用戶基本信息(支持 UnionID 機制)

所以,,艿艿猜測,,之所以圖中畫的是 Implicit Grant 的原因是,受 Google 的 《OAuth 2.0 for Client-side Web Applications》 一文中,,推薦使用了 Implicit Grant ,。

當(dāng)然,具體使用 Implicit Grant 還是 Authorization Code Grant 授權(quán)模式,,沒有定論,。筆者,偏向于使用 Authorization Code Grant,,對于第三方客戶端的場景,。

2. 密碼模式

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo02-authorization-server-with-resource-owner-password-credentials
  • 資源服務(wù)器:lab-68-demo02-resource-server

本小節(jié),我們來學(xué)習(xí)密碼模式(Resource Owner Password Credentials Grant),。

密碼模式,,用戶向客戶端提供自己的用戶名和密碼??蛻舳耸褂眠@些信息,,向授權(quán)服務(wù)器索要授權(quán)。

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

旁白君:如果客戶端和授權(quán)服務(wù)器都是自己公司的,顯然符合,。

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

下面,我們來新建兩個項目,,搭建一個密碼模式的使用示例,。如下圖所示:

項目結(jié)構(gòu)
  • lab-68-demo02-authorization-server-with-resource-owner-password-credentials:授權(quán)服務(wù)器。
  • lab-68-demo02-resource-server:資源服務(wù)器,。

2.1 搭建授權(quán)服務(wù)器

創(chuàng)建 lab-68-demo02-authorization-server-with-resource-owner-password-credentials 項目,,搭建授權(quán)服務(wù)器。

2.1.1 引入依賴

創(chuàng)建 pom.xml 文件,,引入 Spring Security OAuth 依賴,。

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns='http://maven./POM/4.0.0'
         xmlns:xsi='http://www./2001/XMLSchema-instance'
         xsi:schemaLocation='http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd'>

    <parent>
        <artifactId>lab-68</artifactId>
        <groupId>cn.iocoder.springboot.labs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-68-demo02-authorization-server-with-resource-owner-password-credentials</artifactId>

    <properties>
        <!-- 依賴相關(guān)配置 -->
        <spring.boot.version>2.2.4.RELEASE</spring.boot.version>
        <!-- 插件相關(guān)配置 -->
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- 實現(xiàn)對 Spring MVC 的自動配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 實現(xiàn)對 Spring Security OAuth2 的自動配置 -->
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

</project>

添加 spring-security-oauth2-autoconfigure 依賴,引入 Spring Security OAuth 并實現(xiàn)自動配置,。同時,,它也引入了 Spring Security 依賴。如下圖所示:

spring-security-oauth2-autoconfigure

2.1.2 SecurityConfig

創(chuàng)建 SecurityConfig 配置類,,提供一個賬號密碼為「yunai/1024」的用戶,。代碼如下:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public static NoOpPasswordEncoder passwordEncoder() {
        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.
                // 使用內(nèi)存中的 InMemoryUserDetailsManager
                inMemoryAuthentication()
                // 不使用 PasswordEncoder 密碼編碼器
                .passwordEncoder(passwordEncoder())
                // 配置 yunai 用戶
                .withUser('yunai').password('1024').roles('USER');
    }

}

我們通過 Spring Security 提供認(rèn)證功能,所以這里需要配置一個用戶,。

友情提示:看不懂這個配置的胖友,,后續(xù)可回《芋道 Spring Boot 安全框架 Spring Security 入門》重造下。

2.1.3 OAuth2AuthorizationServerConfig

創(chuàng)建 OAuth2AuthorizationServerConfig 配置類,,進行授權(quán)服務(wù)器,。代碼如下:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 用戶認(rèn)證 Manager
     */

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.checkTokenAccess('isAuthenticated()');
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory() // <4.1>
                .withClient('clientapp').secret('112233'// <4.2> Client 賬號、密碼,。
                .authorizedGrantTypes('password'// <4.2> 密碼模式
                .scopes('read_userinfo''read_contacts'// <4.2> 可授權(quán)的 Scope
//                .and().withClient() // <4.3> 可以繼續(xù)配置新的 Client
                ;
    }

}

① 在類上添加 @EnableAuthorizationServer 注解,,聲明開啟 OAuth 授權(quán)服務(wù)器的功能。

同時,,繼承 AuthorizationServerConfigurerAdapter 類,,進行 OAuth 授權(quán)服務(wù)器的配置。

#configure(AuthorizationServerEndpointsConfigurer endpoints) 方法,,配置使用的 AuthenticationManager 實現(xiàn)用戶認(rèn)證的功能,。其中,authenticationManager 是由「2.1.2 SecurityConfig」創(chuàng)建,,Spring Security 的配置類,。

#configure(AuthorizationServerSecurityConfigurer oauthServer) 方法,設(shè)置 /oauth/check_token 端點,,通過認(rèn)證后可訪問,。

友情提示:這里的認(rèn)證,指的是使用 client-id + client-secret 進行的客戶端認(rèn)證,,不要和用戶認(rèn)證混淆,。

其中,,/oauth/check_token 端點對應(yīng) CheckTokenEndpoint 類,用于校驗訪問令牌的有效性,。

  • 在客戶端訪問資源服務(wù)器時,會在請求中帶上訪問令牌,。
  • 在資源服務(wù)器收到客戶端的請求時,,會使用請求中的訪問令牌,找授權(quán)服務(wù)器確認(rèn)該訪問令牌的有效性,。
CheckTokenEndpoint 類

#configure(ClientDetailsServiceConfigurer clients) 方法,,進行 Client 客戶端的配置。

<4.1> 處,,設(shè)置使用基于內(nèi)存的 Client 存儲器,。實際情況下,最好放入數(shù)據(jù)庫中,,方便管理,。

ClientDetailsService 子類

<4.2> 處,創(chuàng)建一個 Client 配置,。如果要繼續(xù)添加另外的 Client 配置,,可以在 <4.3> 處使用 #and() 方法繼續(xù)拼接。注意,,這里的 .withClient('clientapp').secret('112233') 代碼段,,就是 client-idclient-secret

補充知識:可能會有胖友會問,,為什么要創(chuàng)建 Client 的 client-idclient-secret 呢,?

通過 client-id 編號和 client-secret,授權(quán)服務(wù)器可以知道調(diào)用的來源以及正確性,。這樣,,即使“壞人”拿到 Access Token ,但是沒有 client-id 編號和 client-secret,,也不能和授權(quán)服務(wù)器發(fā)生有效的交互,。

2.1.4 AuthorizationServerApplication

創(chuàng)建 AuthorizationServerApplication 類,授權(quán)服務(wù)器的啟動類,。代碼如下:

@SpringBootApplication
public class AuthorizationServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AuthorizationServerApplication.class, args);
    }

}

2.1.5 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器,。下面,我們使用 Postman 模擬一個 Client,。

POST 請求 http://localhost:8080/oauth/token 地址,,使用密碼模式進行授權(quán)。如下圖所示:

  • client-id + client-secret 進行 Client 認(rèn)證
  • 密碼模式的認(rèn)證

請求說明:

  • 通過 Basic Auth 的方式,,填寫 client-id + client-secret 作為用戶名與密碼,,實現(xiàn) Client 客戶端有效性的認(rèn)證,。
  • 請求參數(shù) grant_type'password',表示使用密碼模式,。
  • 請求參數(shù) usernamepassword,,表示用戶的用戶名與密碼。

響應(yīng)說明:

  • 響應(yīng)字段 access_token訪問令牌,,后續(xù)客戶端在訪問資源服務(wù)器時,,通過它作為身份的標(biāo)識。
  • 響應(yīng)字段 token_type令牌類型,,一般是 bearer 或是 mac 類型,。
  • 響應(yīng)字段 expires_in 為訪問令牌的過期時間,單位為秒,。
  • 響應(yīng)字段 scope權(quán)限范圍,。

友情提示:/oauth/token 對應(yīng) TokenEndpoint 端點,提供 OAuth2.0 的四種授權(quán)模式,。感興趣的胖友,,可以后續(xù)去擼擼。

POST 請求 http://localhost:8080/oauth/check_token 地址,,校驗訪問令牌的有效性,。如下圖所示:

  • client-id + client-secret 進行 Client 認(rèn)證
  • 密碼模式的認(rèn)證

請求和響應(yīng)比較簡單,胖友自己瞅瞅即可,。

2.2 搭建資源服務(wù)器

創(chuàng)建 lab-68-demo02-resource-server 項目,,搭建資源服務(wù)器。

2.2.1 引入依賴

創(chuàng)建 pom.xml 文件,,引入 Spring Security OAuth 依賴,。

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns='http://maven./POM/4.0.0'
         xmlns:xsi='http://www./2001/XMLSchema-instance'
         xsi:schemaLocation='http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd'>

    <parent>
        <artifactId>lab-68</artifactId>
        <groupId>cn.iocoder.springboot.labs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-68-demo02-resource-server</artifactId>

    <properties>
        <!-- 依賴相關(guān)配置 -->
        <spring.boot.version>2.2.4.RELEASE</spring.boot.version>
        <!-- 插件相關(guān)配置 -->
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- 實現(xiàn)對 Spring MVC 的自動配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 實現(xiàn)對 Spring Security OAuth2 的自動配置 -->
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

</project>

友情提示:和「2.1.1 引入依賴」小節(jié),是一致的哈,。

2.2.2 配置文件

創(chuàng)建 application.yml 配置文件,,添加 Spring Security OAuth 相關(guān)配置。

server:
  port: 9090

security:
  oauth2:
    # OAuth2 Client 配置,,對應(yīng) OAuth2ClientProperties 類
    client:
      client-id: clientapp
      client-secret: 112233
    # OAuth2 Resource 配置,,對應(yīng) ResourceServerProperties 類
    resource:
      token-info-uri: http://127.0.0.1:8080/oauth/check_token # 獲得 Token 信息的 URL
    # 訪問令牌獲取 URL,自定義的
    access-token-uri: http://127.0.0.1:8080/oauth/token

security.oauth2.client 配置項,,OAuth2 Client 配置,,對應(yīng) OAuth2ClientProperties 類。在這個配置項中,,我們添加了客戶端的 client-idclient-secret,。

為什么要添加這個配置項呢?因為資源服務(wù)器會調(diào)用授權(quán)服務(wù)器的 /oauth/check_token 接口,,而考慮到安全性,,我們配置了該接口需要進過客戶端認(rèn)證,。

友情提示:這里艿艿偷懶了,其實單獨給資源服務(wù)器配置一個 Client 的 client-idclient-secret,。我們可以把資源服務(wù)器理解成授權(quán)服務(wù)器的一個特殊的客戶端,。

security.oauth2.resource 配置項,OAuth2 Resource 配置,,對應(yīng) ResourceServerProperties 類,。

這里,我們通過 token-info-uri 配置項,,設(shè)置使用授權(quán)服務(wù)器的 /oauth/check_token 接口,校驗訪問令牌的有效性,。

security.access-token-uri 配置項,,是我們自定義的,設(shè)置授權(quán)服務(wù)器的 oauth/token 接口,,獲取訪問令牌,。因為稍后我們將在 LoginController 中,實現(xiàn)一個 /login 登錄接口,。

2.2.3 OAuth2ResourceServerConfig

創(chuàng)建 OAuth2ResourceServerConfig 類,,進行資源服務(wù)器。代碼如下:

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            // 設(shè)置 /login 無需權(quán)限訪問
            .antMatchers('/login').permitAll()
            // 設(shè)置其它請求,,需要認(rèn)證后訪問
            .anyRequest().authenticated()
            ;
    }

}

① 在類上添加 @EnableResourceServer 注解,,聲明開啟 OAuth 資源服務(wù)器的功能。

同時,,繼承 ResourceServerConfigurerAdapter 類,,進行 OAuth 資源服務(wù)器的配置。

#configure(HttpSecurity http) 方法,,設(shè)置 HTTP 權(quán)限,。這里,我們設(shè)置 /login 接口無需權(quán)限訪問,,其它接口認(rèn)證后可訪問,。

這樣,客戶端在訪問資源服務(wù)器時,,其請求中的訪問令牌會被資源服務(wù)器調(diào)用授權(quán)服務(wù)器的 /oauth/check_token 接口,,進行校驗訪問令牌的正確性。

2.2.4 ExampleController

創(chuàng)建 ExampleController 類,,提供 /api/example/hello 接口,,表示一個資源。代碼如下:

@RestController
@RequestMapping('/api/example')
public class ExampleController {

    @RequestMapping('/hello')
    public String hello() {
        return 'world';
    }

}

2.2.5 ResourceServerApplication

創(chuàng)建 ResourceServerApplication 類,,資源服務(wù)器的啟動類,。代碼如下:

@SpringBootApplication
public class ResourceServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourceServerApplication.class, args);
    }

}

2.2.6 簡單測試(第一彈)

執(zhí)行 ResourceServerApplication 啟動資源服務(wù)器,。下面,我們來請求服務(wù)器的 <127.0.0.1:9090/api/example/hello> 接口,,進行相應(yīng)的測試,。

① 首先,請求 <127.0.0.1:9090/api/example/hello> 接口,,不帶訪問令牌,,則請求會被攔截。如下圖所示:

不帶訪問令牌

② 然后,,請求 <127.0.0.1:9090/api/example/hello> 接口,,帶上錯誤的訪問令牌,則請求會被攔截,。如下圖所示:

錯誤的訪問令牌

友情提示:訪問令牌需要在請求頭 'Authorization' 上設(shè)置,,并且以 'Bearer ' 開頭。

③ 最后,,請求 <127.0.0.1:9090/api/example/hello> 接口,,帶上正確的訪問令牌,則請求會被通過,。如下圖所示:

正確的訪問令牌

2.2.7 LoginController

創(chuàng)建 LoginController 類,,提供 /login 登錄接口。代碼如下:

@RestController
@RequestMapping('/')
public class LoginController {

    @Autowired
    private OAuth2ClientProperties oauth2ClientProperties;

    @Value('${security.oauth2.access-token-uri}')
    private String accessTokenUri;

    @PostMapping('/login')
    public OAuth2AccessToken login(@RequestParam('username') String username,
                                   @RequestParam('password') String password) 
{
        // <1> 創(chuàng)建 ResourceOwnerPasswordResourceDetails 對象
        ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
        resourceDetails.setAccessTokenUri(accessTokenUri);
        resourceDetails.setClientId(oauth2ClientProperties.getClientId());
        resourceDetails.setClientSecret(oauth2ClientProperties.getClientSecret());
        resourceDetails.setUsername(username);
        resourceDetails.setPassword(password);
        // <2> 創(chuàng)建 OAuth2RestTemplate 對象
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
        restTemplate.setAccessTokenProvider(new ResourceOwnerPasswordAccessTokenProvider());
        // <3> 獲取訪問令牌
        return restTemplate.getAccessToken();
    }

}

/login 接口中,,資源服務(wù)器扮演的是一個 OAuth 客戶端的角色,,調(diào)用授權(quán)服務(wù)器的 /oauth/token 接口,使用密碼模式進行授權(quán),,獲得訪問令牌,。

<1> 處,創(chuàng)建 ResourceOwnerPasswordResourceDetails 對象,,填寫密碼模式授權(quán)需要的請求參數(shù),。

<2> 處,創(chuàng)建 OAuth2RestTemplate 對象,,它是 Spring Security OAuth 封裝的工具類,,用于請求授權(quán)服務(wù)器。

同時,,將 ResourceOwnerPasswordAccessTokenProvider 設(shè)置到其中,,表示使用密碼模式授權(quán)。

友情提示:這一步非常重要,,艿艿在這里卡了非常非常非常久,,一度自閉要放棄。

<3> 處,,調(diào)用 OAuth2RestTemplate 的 #getAccessToken() 方法,,調(diào)用授權(quán)服務(wù)器的 /oauth/token 接口,,進行密碼模式的授權(quán)。

注意,,OAuth2RestTemplate 是有狀態(tài)的工具類,,所以需要每次都重新創(chuàng)建。

2.2.8 簡單測試(第二彈)

重新執(zhí)行 ResourceServerApplication 啟動資源服務(wù)器,。下面,,我們來進行 /login 接口的測試。

① 首先,,請求 http://127.0.0.1:9090/login 接口,,使用用戶用戶名密碼進行登錄,獲得訪問令牌,。如下圖所示:

測試 /login 接口

響應(yīng)結(jié)果和授權(quán)服務(wù)器的 /oauth/token 接口是一致的,,因為就是調(diào)用它,嘿嘿~

② 然后,,請求 <127.0.0.1:9090/api/example/hello> 接口,帶剛剛的訪問令牌,,則請求會被通過,。如下圖所示:

正確的訪問令牌

3. 授權(quán)碼模式

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo02-authorization-server-with-resource-owner-password-credentials
  • 資源服務(wù)器:lab-68-demo02-resource-server

本小節(jié),我們來學(xué)習(xí)授權(quán)碼模式(Authorization Code),。

授權(quán)碼模式,,是功能最完整、流程最嚴(yán)密的授權(quán)模式,。它的特點就是通過客戶端的后臺服務(wù)器,,與授權(quán)務(wù)器進行互動。

旁白君:一般情況下,,在有客戶端的情況下,,我們與第三方平臺常常采用這種方式。

授權(quán)碼模式
  • (A)用戶訪問客戶端,,后者將前者跳轉(zhuǎn)到到授權(quán)服務(wù)器,。
  • (B)用戶選擇是否給予客戶端授權(quán)。
  • (C)假設(shè)用戶給予授權(quán),,授權(quán)服務(wù)器將跳轉(zhuǎn)到客戶端事先指定的'重定向 URI'(Redirection URI),,同時附上一個授權(quán)碼
  • (D)客戶端收到授權(quán)碼,,附上早先的'重定向 URI',,向認(rèn)證服務(wù)器申請令牌。這一步是在客戶端的后臺的服務(wù)器上完成的,,對用戶不可見,。
  • (E)認(rèn)證服務(wù)器核對了授權(quán)碼重定向 URI,,確認(rèn)無誤后,向客戶端發(fā)送訪問令牌,。

下面,,我們來新建兩個項目,搭建一個授權(quán)碼模式的使用示例,。如下圖所示:

項目結(jié)構(gòu)
  • lab-68-demo02-authorization-server-with-resource-owner-password-credentials:授權(quán)服務(wù)器,。
  • lab-68-demo02-resource-server:資源服務(wù)器。

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

復(fù)制出 lab-68-demo02-authorization-server-with-resource-owner-password-credentials 項目,,修改搭建授權(quán)服務(wù)器,。改動點如下圖所示:

項目改動點

僅僅需要修改 OAuth2AuthorizationServerConfig 類,設(shè)置使用 'authorization_code' 授權(quán)碼模式,,并設(shè)置回調(diào)地址,。

?? 注意,這里設(shè)置的回調(diào)地址,,稍后我們會在「3.2 搭建資源服務(wù)器」中實現(xiàn),。

3.1.1 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器。

① 使用瀏覽器,,訪問 http://127.0.0.1:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://127.0.0.1:9090/callback&response_type=code&scope=read_userinfo 地址,,獲取授權(quán)。請求參數(shù)說明如下:

  • client_id 參數(shù),,必傳,,為我們在 OAuth2AuthorizationServer 中配置的 Client 的編號。
  • redirect_uri 參數(shù),,可選,,回調(diào)地址。當(dāng)然,,如果 client_id 對應(yīng)的 Client 未配置 redirectUris 屬性,,會報錯。
  • response_type 參數(shù),,必傳,,返回結(jié)果為 code 授權(quán)碼
  • scope 參數(shù),,可選,,申請授權(quán)的 Scope 。如果多個,,使用逗號分隔,。
  • state 參數(shù),可選,表示客戶端的當(dāng)前狀態(tài),,可以指定任意值,,授權(quán)服務(wù)器會原封不動地返回這個值。

友情提示:state 參數(shù),,未在上述 URL 中體現(xiàn)出來,。

因為我們并未登錄授權(quán)服務(wù)器,所以被攔截跳轉(zhuǎn)到登錄界面,。如下圖所示:

登錄界面

② 輸入用戶的賬號密碼「yunai/1024」進行登錄,。登錄完成后,進入授權(quán)界面,。如下圖所示:

旁白君:和我們?nèi)粘J褂玫尿v訊 QQ,、微信、微博等等三方登錄,,是一模一樣的,,除了丑了點,嘿嘿~

授權(quán)界面

③ 選擇 scope.read_userinfo 為 Approve 允許,,點擊「Authorize」按鈕,,完成授權(quán)操作。瀏覽器自動重定向到 Redirection URI 地址,,并且在 URI 上可以看到 code 授權(quán)碼,。如下圖所示:

回調(diào)界面

友情提示:/oauth/authorize 對應(yīng) AuthorizationEndpoint 端點。

④ 因為我們暫時沒有啟動資源服務(wù)器,,所以顯示無法訪問。這里,,我們先使用 Postman 模擬請求 http://localhost:8080/oauth/token 地址,,使用授權(quán)碼獲取到訪問令牌。如下圖所示:

  • client-id + client-secret 進行 Client 認(rèn)證
  • 授權(quán)碼模式的認(rèn)證

請求說明:

  • 通過 Basic Auth 的方式,,填寫 client-id + client-secret 作為用戶名與密碼,,實現(xiàn) Client 客戶端有效性的認(rèn)證。
  • 請求參數(shù) grant_type'authorization_code',,表示使用授權(quán)碼模式,。
  • 請求參數(shù) code,從授權(quán)服務(wù)器獲取到的授權(quán)碼,。
  • 請求參數(shù) redirect_uri,,Client 客戶端的 Redirection URI 地址。

注意,,授權(quán)碼僅能使用一次,,重復(fù)請求會報 Invalid authorization code: 錯誤。如下圖所示:

授權(quán)碼模式的認(rèn)證 - 失敗

3.2 搭建資源服務(wù)器

復(fù)用 lab-68-demo02-resource-server 項目,,主要是提供回調(diào)地址,。如下圖所示:

項目改動點

① 新建 CallbackController 類,,提供 /callback 回調(diào)地址。

② 在 OAuth2ResourceServerConfig 配置類中,,設(shè)置 /callback 回調(diào)地址無需權(quán)限驗證,,不然回調(diào)都跳轉(zhuǎn)不過來哈。

3.2.1 CallbackController

創(chuàng)建 CallbackController 類,,提供 /callback 回調(diào)地址,,在獲取到授權(quán)碼時,請求授權(quán)服務(wù)器,,通過授權(quán)碼獲取訪問令牌,。代碼如下:

@RestController
@RequestMapping('/')
public class CallbackController {

    @Autowired
    private OAuth2ClientProperties oauth2ClientProperties;

    @Value('${security.oauth2.access-token-uri}')
    private String accessTokenUri;

    @GetMapping('/callback')
    public OAuth2AccessToken login(@RequestParam('code') String code) {
        // 創(chuàng)建 AuthorizationCodeResourceDetails 對象
        AuthorizationCodeResourceDetails resourceDetails = new AuthorizationCodeResourceDetails();
        resourceDetails.setAccessTokenUri(accessTokenUri);
        resourceDetails.setClientId(oauth2ClientProperties.getClientId());
        resourceDetails.setClientSecret(oauth2ClientProperties.getClientSecret());
        // 創(chuàng)建 OAuth2RestTemplate 對象
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
        restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAuthorizationCode(code); // <1> 設(shè)置 code
        restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setPreservedState('http://127.0.0.1:9090/callback'); // <2> 通過這個方式,設(shè)置 redirect_uri 參數(shù)
        restTemplate.setAccessTokenProvider(new AuthorizationCodeAccessTokenProvider());
        // 獲取訪問令牌
        return restTemplate.getAccessToken();
    }

}

代碼比較簡單,,還是使用 OAuth2RestTemplate 進行請求授權(quán)服務(wù)器,,胖友自己瞅瞅哈。

需要注意的是 <1><2> 處,,設(shè)置請求授權(quán)服務(wù)器需要的 coderedirect_uri 參數(shù),。

3.2.2 簡單測試

執(zhí)行 ResourceServerApplication 啟動資源服務(wù)器。

重復(fù)「3.2.1 簡單測試」的過程,,成功獲取到訪問令牌,。如下圖所示:

授權(quán)碼模式的認(rèn)證 - 成功

4. 簡化模式

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo02-authorization-server-with-implicit
  • 資源服務(wù)器:lab-68-demo02-resource-server

本小節(jié),我們來學(xué)習(xí)簡化模式(Implicit),。

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

簡化模式
  • (A)用戶訪問客戶端,,后者將前者跳轉(zhuǎn)到到授權(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ā)給客戶端,。
項目結(jié)構(gòu)
  • lab-68-demo02-authorization-server-with-implicit:授權(quán)服務(wù)器,。
  • lab-68-demo02-resource-server:資源服務(wù)器。

4.1 搭建授權(quán)服務(wù)器

復(fù)制出 lab-68-demo02-authorization-server-with-implicit 項目,,修改搭建授權(quán)服務(wù)器,。改動點如下圖所示:

項目改動點

僅僅需要修改 OAuth2AuthorizationServerConfig 類,設(shè)置使用 'implicit' 簡化模式,,并設(shè)置回調(diào)地址,。

?? 注意,這里設(shè)置的回調(diào)地址,,稍后我們會在「4.2 搭建資源服務(wù)器」中實現(xiàn),。

4.2 搭建資源服務(wù)器

復(fù)用 lab-68-demo02-resource-server 項目,主要是提供回調(diào)地址,。如下圖所示:

項目改動點

① 新建 Callback02Controller 類,,提供 /callback02 回調(diào)地址。代碼如下:

@RestController
@RequestMapping('/')
public class Callback02Controller {

    @GetMapping('/callback02')
    public String login() {
        return '假裝這里有一個頁面';
    }

}

友情提示:考慮到暫時不想做頁面,,所以這里先假裝一下,,嘿嘿。

② 在 OAuth2ResourceServerConfig 配置類中,,設(shè)置 /callback02 回調(diào)地址無需權(quán)限驗證,,不然回調(diào)都跳轉(zhuǎn)不過來哈。

4.3 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器,。
執(zhí)行 ResourceServerApplication 啟動資源服務(wù)器,。

① 使用瀏覽器,訪問 http://127.0.0.1:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://127.0.0.1:9090/callback02&response_type=token&scope=read_userinfo 地址,,獲取授權(quán)。請求參數(shù)說明如下:

  • client_id 參數(shù),,必傳,,為我們在 OAuth2AuthorizationServer 中配置的 Client 的編號。
  • redirect_uri 參數(shù),,可選,,回調(diào)地址。當(dāng)然,,如果 client_id 對應(yīng)的 Client 未配置 redirectUris 屬性,,會報錯。
  • response_type 參數(shù),必傳,,返回結(jié)果為 token 訪問令牌,。
  • scope 參數(shù),可選,,申請授權(quán)的 Scope ,。如果多個,使用逗號分隔,。
  • state 參數(shù),,可選,表示客戶端的當(dāng)前狀態(tài),,可以指定任意值,,授權(quán)服務(wù)器會原封不動地返回這個值。

友情提示:state 參數(shù),,未在上述 URL 中體現(xiàn)出來,。

因為我們并未登錄授權(quán)服務(wù)器,所以被攔截跳轉(zhuǎn)到登錄界面,。如下圖所示:

登錄界面

② 輸入用戶的賬號密碼「yunai/1024」進行登錄,。登錄完成后,進入授權(quán)界面,。如下圖所示:

旁白君:和我們?nèi)粘J褂玫尿v訊 QQ,、微信、微博等等三方登錄,,是一模一樣的,,除了丑了點,嘿嘿~

授權(quán)界面

③ 選擇 scope.read_userinfo 為 Approve 允許,,點擊「Authorize」按鈕,,完成授權(quán)操作。瀏覽器自動重定向到 Redirection URI 地址,,并且在 URI 上的 Hash 部分可以看到 access_token 訪問令牌,。如下圖所示:

回調(diào)界面

后續(xù),可以通過編寫 Javascript 腳本的代碼,,獲取 URI 上的 Hash 部分的訪問令牌,。

5. 客戶端模式

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo02-authorization-server-with-client-credentials
  • 資源服務(wù)器:lab-68-demo02-resource-server

本小節(jié),我們來學(xué)習(xí)客戶端模式(Client Credentials),。

客戶端模式,,指客戶端以自己的名義,而不是以用戶的名義,,向授權(quán)服務(wù)器進行認(rèn)證,。

嚴(yán)格地說,,客戶端模式并不屬于 OAuth 框架所要解決的問題。在這種模式中,,用戶直接向客戶端注冊,,客戶端以自己的名義要求授權(quán)服務(wù)器提供服務(wù),其實不存在授權(quán)問題,。

旁白君:我們對接微信公眾號時,,就采用的客戶端模式。我們的后端服務(wù)器就扮演“客戶端”的角色,,與微信公眾號的后端服務(wù)器進行交互,。

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

下面,,我們來新建兩個項目,,搭建一個客戶端模式的使用示例。如下圖所示:

項目結(jié)構(gòu)
  • lab-68-demo02-authorization-server-with-client-credentials:授權(quán)服務(wù)器,。
  • lab-68-demo02-resource-server:資源服務(wù)器,。

5.1 搭建授權(quán)服務(wù)器

復(fù)制出 lab-68-demo02-authorization-server-with-client-credentials 項目,修改搭建授權(quán)服務(wù)器,。改動點如下圖所示:

項目改動點

① 刪除 SecurityConfig 配置類,,因為客戶端模式下,無需 Spring Security 提供用戶的認(rèn)證功能,。

但是,,Spring Security OAuth 需要一個 PasswordEncoder Bean,否則會報錯,,因此我們在 OAuth2AuthorizationServerConfig 類的 #passwordEncoder() 方法進行創(chuàng)建,。

② 修改 OAuth2AuthorizationServerConfig 類,設(shè)置使用 'client_credentials' 客戶端模式,。

5.1.1 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器,。下面,我們使用 Postman 模擬一個 Client,。

POST 請求 http://localhost:8080/oauth/token 地址,,使用客戶端模式進行授權(quán)。如下圖所示:

  • client-id + client-secret 進行 Client 認(rèn)證
  • 客戶端模式的認(rèn)證

請求說明:

  • 通過 Basic Auth 的方式,,填寫 client-id + client-secret 作為用戶名與密碼,實現(xiàn) Client 客戶端有效性的認(rèn)證,。
  • 請求參數(shù) grant_type'client_credentials',,表示使用客戶端模式,。

響應(yīng)就是訪問令牌,胖友自己瞅瞅即可,。

5.2 搭建資源服務(wù)器

復(fù)用 lab-68-demo02-resource-server 項目,,修改點如下圖所示:

項目改動點

① 新建 ClientLoginController 類,提供 /client-login 接口,,實現(xiàn)調(diào)用授權(quán)服務(wù)器,,進行客戶端模式的授權(quán),獲得訪問令牌,。代碼如下:

@RestController
@RequestMapping('/')
public class ClientLoginController {

    @Autowired
    private OAuth2ClientProperties oauth2ClientProperties;

    @Value('${security.oauth2.access-token-uri}')
    private String accessTokenUri;

    @PostMapping('/client-login')
    public OAuth2AccessToken login() {
        // 創(chuàng)建 ClientCredentialsResourceDetails 對象
        ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
        resourceDetails.setAccessTokenUri(accessTokenUri);
        resourceDetails.setClientId(oauth2ClientProperties.getClientId());
        resourceDetails.setClientSecret(oauth2ClientProperties.getClientSecret());
        // 創(chuàng)建 OAuth2RestTemplate 對象
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
        restTemplate.setAccessTokenProvider(new ClientCredentialsAccessTokenProvider());
        // 獲取訪問令牌
        return restTemplate.getAccessToken();
    }

}

代碼比較簡單,,還是使用 OAuth2RestTemplate 進行請求授權(quán)服務(wù)器,胖友自己瞅瞅哈,。

② 在 OAuth2ResourceServerConfig 配置類中,,設(shè)置 /client-login 接口無需權(quán)限驗證,不然無法調(diào)用哈,。

5.2.1 簡單測試

執(zhí)行 ResourceServerApplication 啟動資源服務(wù)器,。

① 使用「5.1.1 簡單測試」小節(jié)獲得的訪問令牌,請求 <127.0.0.1:9090/api/example/hello> 接口時帶上,,則請求會被通過,。如下圖所示:

正確的訪問令牌

② 請求 http://127.0.0.1:9090/clientlogin 接口,使用客戶端模式進行授權(quán),,獲得訪問令牌,。如下圖所示:

測試 client-login 接口

響應(yīng)結(jié)果和授權(quán)服務(wù)器的 /oauth/token 接口是一致的,因為就是調(diào)用它,,嘿嘿~

6. 合并服務(wù)器

旁白君:這個小節(jié)的標(biāo)題,,艿艿有點不知道怎么取了,就先叫合并服務(wù)器吧 = =,!

在項目比較小時,,考慮到節(jié)省服務(wù)器資源,會考慮將授權(quán)服務(wù)器和資源服務(wù)器合并到一個項目中,,避免啟動多個 Java 進程,。良心的艿艿,編寫了四種授權(quán)模式的示例,,如下圖所示:

示例項目
  • 基于密碼模式的示例:lab-68-demo01-resource-owner-password-credentials-server
  • 基于授權(quán)碼模式的示例:lab-68-demo01-authorization-code-server
  • 基于簡化模式的示例:lab-68-demo01-implicit-server
  • 基于客戶端模式的示例:lab-68-demo01-client-credentials-server

具體的代碼實現(xiàn),,實際和上述每個授權(quán)模式對應(yīng)的小節(jié)是基本一致的,只是說將代碼“”在了一個項目中,。嘿嘿~

7. 刷新令牌

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo03-authorization-server-with-client-credentials

在 OAuth2.0 中,,一共有兩類令牌:

  • 訪問令牌(Access Token)
  • 刷新令牌(Refresh Token)

訪問令牌過期時,我們可以使用刷新令牌向授權(quán)服務(wù)器獲取一個的訪問令牌,。

可能會胖友有疑惑,,為什么會有刷新令牌呢,?每次請求資源服務(wù)器時,都會在請求上帶上訪問令牌,,這樣它的泄露風(fēng)險是相對高的,。

因此,出于安全性的考慮,,訪問令牌的過期時間比較短,,刷新令牌的過期時間比較長。這樣,,如果訪問令牌即使被盜用走,,那么在一定的時間后,訪問令牌也能在較短的時間吼過期,。當(dāng)然,,安全也是相對的,如果使用刷新令牌后,,獲取到新的訪問令牌,,訪問令牌后續(xù)可能被盜用。

艿艿整理了下,,大家常用開放平臺的令牌過期時間,,讓大家更好的理解:

開放平臺Access Token 有效期Refresh Token 有效期
微信開放平臺2 小時未知
騰訊開放平臺90 天未知
小米開放平臺90 天10 年

7.1 示例項目

下面,復(fù)制出 lab-68-demo03-authorization-server-with-client-credentials 項目,,搭建提供訪問令牌授權(quán)服務(wù)器。改動點如下圖所示:

項目改動點

① 在 OAuth2AuthorizationServerConfig 的 #configure(ClientDetailsServiceConfigurer clients) 方法中,,在配置的 Client 的授權(quán)模式中,,額外新增 'refresh_token' 刷新令牌。

通過 #accessTokenValiditySeconds(int accessTokenValiditySeconds) 方法,,設(shè)置訪問令牌的有效期,。
通過 #refreshTokenValiditySeconds(int refreshTokenValiditySeconds) 方法,設(shè)置刷新令牌的有效期,。

② 在 OAuth2AuthorizationServerConfig 的 #configure(AuthorizationServerEndpointsConfigurer endpoints) 方法中,,設(shè)置使用的 userDetailsService 用戶詳情 Service。

而該 userDetailsService 是在 SecurityConfig 的 #userDetailsServiceBean() 方法創(chuàng)建的 UserDetailsService Bean,。

友情提示:如果不進行 UserDetailsService 的設(shè)置,,在使用刷新令牌獲取新的訪問令牌時,會拋出異常,。

7.2 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器,。下面,我們使用 Postman 模擬一個 Client,。

POST 請求 http://localhost:8080/oauth/token 地址,,使用密碼模式進行授權(quán),。如下圖所示:

密碼模式的認(rèn)證

額外多返回了 refresh_token 刷新令牌。

POST 請求 http://localhost:8080/oauth/token 地址,,使用刷新令牌模式進行授權(quán)。如下圖所示:

刷新令牌模式的認(rèn)證

請求說明:

  • 通過 Basic Auth 的方式,,填寫 client-id + client-secret 作為用戶名與密碼,實現(xiàn) Client 客戶端有效性的認(rèn)證,。
  • 請求參數(shù) grant_type'refresh_token',,表示使用刷新令牌模式
  • 請求參數(shù) refresh_token,,表示刷新令牌,。

在響應(yīng)中,,返回了新的 access_token 訪問令牌。注意,,老的 access_token 訪問令牌會失效,,無法繼續(xù)使用。

8. 刪除令牌

示例代碼對應(yīng)倉庫:

  • 授權(quán)服務(wù)器:lab-68-demo03-authorization-server-with-client-credentials

在用戶登出系統(tǒng)時,,我們會有刪除令牌的需求,。雖然說,,可以通過客戶端本地刪除令牌的方式實現(xiàn)。但是,,考慮到真正的徹底的實現(xiàn)刪除令牌,,必然服務(wù)端自身需要刪除令牌。

友情提示:客戶端本地刪除令牌的方式實現(xiàn),,指的是清楚本地 Cookie,、localStorage 的令牌緩存。

在 Spring Security OAuth2 中,,并沒有提供內(nèi)置的接口,,所以需要自己去實現(xiàn)。筆者參看 《Spring Security OAuth2 – Simple Token Revocation》 文檔,,實現(xiàn)刪除令牌的 API 接口,。

具體的實現(xiàn),通過調(diào)用 ConsumerTokenServices 的 #revokeToken(String tokenValue) 方法,,刪除訪問令牌和刷新令牌,。如下圖所示:

ConsumerTokenServices 實現(xiàn)類

8.1 示例項目

下面,我們直接在授權(quán)服務(wù)器 lab-68-demo03-authorization-server-with-resource-owner-password-credentials 項目,,修改接入刪除令牌的功能,。改動點如下圖所示:

項目改動點

① 創(chuàng)建 TokenDemoController 類,提供 /token/demo/revoke 接口,,調(diào)用 ConsumerTokenServices 的 #revokeToken(String tokenValue) 方法,,刪除訪問令牌和刷新令牌。代碼如下:

@RestController
@RequestMapping('/token/demo')
public class TokenDemoController {

    @Autowired
    private ConsumerTokenServices tokenServices;

    @PostMapping(value = '/revoke')
    public boolean revokeToken(@RequestParam('token') String token) {
        return tokenServices.revokeToken(token);
    }

}

② 在 SecurityConfig 配置類,,設(shè)置 /token/demo/revoke 接口無需授權(quán),,方便測試。代碼如下:

// SecurityConfig.java

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            // 設(shè)置 /token/demo/revoke 無需授權(quán)
            .mvcMatchers('/token/demo/revoke').permitAll()
            // 設(shè)置其它接口需要授權(quán)
            .anyRequest().authenticated();
}

8.2 簡單測試

執(zhí)行 AuthorizationServerApplication 啟動授權(quán)服務(wù)器,。下面,,我們使用 Postman 模擬一個 Client

POST 請求 http://localhost:8080/oauth/token 地址,,使用密碼模式進行授權(quán),。如下圖所示:

密碼模式的認(rèn)證

POST 請求 http://localhost:8080/token/demo/revoke 地址,刪除令牌,。如下圖所示:

刪除令牌

刪除成功,。后續(xù),胖友可以自己調(diào)用授權(quán)服務(wù)器的 oauth/check_token 接口,,測試訪問令牌是否已經(jīng)被刪除,。

666. 彩蛋

至此,我們完整學(xué)習(xí) Spring Security OAuth 框架,。不過 Spring 團隊宣布該框架處于 Deprecation 廢棄狀態(tài),。如下圖所示:

Spring Security OAuth 被廢棄

同時,Spring 團隊正在實現(xiàn)新的 Spring Authorization Server 授權(quán)服務(wù)器,,目前還處于 Experimental 實驗狀態(tài),。

實際項目中,根據(jù)艿艿了解到的情況,,很少項目會直接采用 Spring Security OAuth 框架,,而是自己參考它進行 OAuth2.0 的實現(xiàn)。并且,,一般只會實現(xiàn)密碼授權(quán)模式,。


在本文中,我們采用基于內(nèi)存的 InMemoryTokenStore,,實現(xiàn)訪問令牌和刷新令牌的存儲,。它會存在兩個明顯的缺點

  • 重啟授權(quán)服務(wù)器時,令牌信息會丟失,導(dǎo)致用戶需要重新授權(quán),。
  • 多個授權(quán)服務(wù)器時,,令牌信息無法共享,導(dǎo)致用戶一會授權(quán)成功,,一會授權(quán)失敗,。

因此,下一篇《芋道 Spring Security OAuth2 存儲器》文章,,我們來學(xué)習(xí) Spring Security OAuth 提供的基于數(shù)據(jù)庫Redis的存儲器,。走起~


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多