Spring Cloud入門教程(十一):微服務(wù)安全(Security)

Spring Cloud入門教程系列:

本人和同事撰寫的《Spring Cloud微服務(wù)架構(gòu)開發(fā)實(shí)戰(zhàn)》一書也在京東、當(dāng)當(dāng)?shù)葧晟霞埽蠹铱梢渣c(diǎn)擊這里前往購買,多謝大家支持和捧場(chǎng)!


安全,幾乎在任何應(yīng)用開發(fā)中都是繞不過去的一個(gè)基礎(chǔ)功能。當(dāng)我們將應(yīng)用轉(zhuǎn)移到微服務(wù)架構(gòu)時(shí),安全將會(huì)更加復(fù)雜。在2016年David Borsos在倫敦的微服務(wù)大會(huì)上提出了以下四種方案:

  1. 單點(diǎn)登錄(SSO): 每個(gè)微服務(wù)都需要和認(rèn)證服務(wù)交互,但這將產(chǎn)生大量非常瑣碎的網(wǎng)絡(luò)流量和重復(fù)的工作,當(dāng)動(dòng)在應(yīng)用中存在數(shù)十個(gè)或更多微服務(wù)時(shí),該方案的弊端就非常明顯;

  2. 分布式會(huì)話(Session)方案: 該方案將用戶認(rèn)證的信息存儲(chǔ)在共享存儲(chǔ)中(如:Redis),并使用用戶會(huì)話的ID作為key來實(shí)現(xiàn)的簡(jiǎn)單分布式哈希映射。當(dāng)用戶訪問微服務(wù)時(shí),可以通過會(huì)話的ID從從共享存儲(chǔ)中獲取用戶認(rèn)證信息。該方案在大部分時(shí)候非常不錯(cuò),但其主要缺點(diǎn)在于共享存儲(chǔ)需要一定保護(hù)機(jī)制,此時(shí)相應(yīng)的實(shí)現(xiàn)就會(huì)相對(duì)復(fù)雜;

  3. 客戶端令牌(Token)方案: 令牌在客戶端生成,并由認(rèn)證服務(wù)器進(jìn)行簽名,令牌中包含足夠的信息,以便各微服務(wù)可以使用。令牌會(huì)附加到每個(gè)請(qǐng)求上,為微服務(wù)提供用戶身份驗(yàn)證。該解決方案的安全性相對(duì)較好,但由于令牌由客戶端生成并保存,因此身份驗(yàn)證注銷非常麻煩,一個(gè)折衷解決方案就是通過短期令牌和頻繁檢查認(rèn)證服務(wù)來驗(yàn)證令牌是否有效等。對(duì)于客戶端令牌JSON Web Tokens(JWT)是一個(gè)非常好的選擇;

  4. 客戶端令牌與API網(wǎng)關(guān)結(jié)合: 使用該方案意味著所有請(qǐng)求都通過網(wǎng)關(guān),從而有效地隱藏了微服務(wù)。在請(qǐng)求時(shí),網(wǎng)關(guān)將原始用戶令牌轉(zhuǎn)換為內(nèi)部會(huì)話。這樣也就可以網(wǎng)關(guān)對(duì)令牌進(jìn)行注銷,從而解決上一種方案存在的問題。

在本文中我們將著重介紹基于令牌的解決方案,而基于令牌的解決方案最好的選擇就是OAuth2.0。

1. OAuth2.0

關(guān)于OAuth2.0在維基百科中描述如下:

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

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

OAuth 2.0是OAuth協(xié)議的下一版本,但不向下兼容OAuth 1.0。OAuth 2.0關(guān)注客戶端開發(fā)者的簡(jiǎn)易性,同時(shí)為Web應(yīng)用,桌面應(yīng)用和手機(jī),和起居室設(shè)備提供專門的認(rèn)證流程。

對(duì)于讓我們首先了解一下OAuth2.0中的幾個(gè)關(guān)鍵術(shù)語:

  • Resource Owner: 資源所有者,我們可以直接理解為:用戶(User);
  • User Agent: 用戶代理,對(duì)于Web應(yīng)用可以直接理解為瀏覽器;
  • Authorization server: 認(rèn)證服務(wù)器,即提供用戶認(rèn)證和授權(quán)的服務(wù)器,可以是獨(dú)立服務(wù)器;
  • Resource server: 資源服務(wù)器,這里我們可以理解為需要保護(hù)的微服務(wù)。

然后,讓我們看一下OAuth2.0的認(rèn)證流程圖(摘自RFC6749):

Security-OAuth2-010.png

認(rèn)證流程步驟如下:

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

從流程上可以得知客戶端必須在得到用戶授權(quán)后才能夠從認(rèn)證服務(wù)中獲取到令牌。OAuth2.0針對(duì)客戶端授權(quán)提供了下面四種授權(quán)方式:

  1. 授權(quán)碼模式(authorization code): 該種模式是功能最完整、流程最嚴(yán)密的授權(quán)模式;
  2. 簡(jiǎn)化模式(implicit): 該模式不需要通過第三方應(yīng)用程序的服務(wù)器,跳過了"授權(quán)碼"這個(gè)步驟,直接在瀏覽器中向認(rèn)證服務(wù)器申請(qǐng)令牌,因此稱為簡(jiǎn)化模式;
  3. 密碼模式(password): 用戶向客戶端提供自己的用戶名和密碼,客戶端通過這些信息直接向認(rèn)證服務(wù)器獲取授權(quán);
  4. 客戶端模式(client credentials): 指客戶端以自己的名義,而不是以用戶的名義向認(rèn)證服務(wù)器獲取認(rèn)證,這種方式下認(rèn)證服務(wù)器會(huì)將客戶端作為一個(gè)用戶來對(duì)待。

2. 實(shí)現(xiàn)微服務(wù)安全

下面讓我們著手來實(shí)現(xiàn)示例項(xiàng)目的安全管控。

2.1 搭建認(rèn)證服務(wù)器

首先,我們會(huì)搭建一個(gè)認(rèn)證服務(wù)器(Auth Server)。該服務(wù)器也是一個(gè)標(biāo)準(zhǔn)的Spring Boot框架應(yīng)用。

2.1.1 編寫Maven文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>twostepsfromjava.cloud</groupId>
        <artifactId>twostepsfromjava-cloud-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../parent</relativePath>
    </parent>

    <artifactId>auth-server</artifactId>
    <name>MS Blog Projects(Security): Auth Server</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

在該配置文件中我們需要引入spring-cloud-securityspring-security-oauth2依賴。

2.1.2 實(shí)現(xiàn)客戶端管理

對(duì)于OAuth2.0應(yīng)用來說需要實(shí)現(xiàn)一個(gè)客戶端認(rèn)證管理,這里我們直接繼承AuthorizationServerConfigurerAdapter,并通過內(nèi)存管理的方式增加了一個(gè)客戶端應(yīng)用,代碼如下:

package io.twostepsfromjava.cloud.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;


/**
 * OAuth2Server 配置
 *
 * @author CD826(CD826Dong@gmail.com)
 * @since 1.0.0
 */
@Configuration
public class OAuthConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("malldemo")
                .secret("pgDBd99tOX8d")
                .authorizedGrantTypes("authorization_code", "refresh_token", "implicit", "password", "client_credentials")
                .scopes("webmall");
    }

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

客戶端ID我們?cè)O(shè)置為malldemo,secret則設(shè)置為:pgDBd99tOX8d,同時(shí)我們還為客戶端授權(quán)了authorization_code, refresh_token, implicit, password, client_credentials認(rèn)證模式。并且在接下來的示例中我們會(huì)使用授權(quán)碼模式和密碼模式來進(jìn)行測(cè)試。

2.1.3 實(shí)現(xiàn)用戶認(rèn)證和授權(quán)的管理

對(duì)于使用過Spring Security的同學(xué)來說對(duì)Security中用戶認(rèn)證和授權(quán)的管理應(yīng)該不會(huì)陌生,這里也不再細(xì)講,不熟悉的同學(xué)可以自行搜索來了解。示例中代碼如下:

package io.twostepsfromjava.cloud.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;


/**
 * OAuth2 安全配置
 *
 * @author CD826(CD826Dong@gmail.com)
 * @since 1.0.0
 */
@Configuration
@Order(org.springframework.boot.autoconfigure.security.SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class OAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception{
        return super.authenticationManagerBean();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user001")
                .password("pwd001")
                .roles("USER")
                .and()
                .withUser("admin")
                .password("pwdAdmin")
                .roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();
    }
}

在上面的代碼中,我們依然通過內(nèi)存方式進(jìn)行管理,并創(chuàng)建了兩個(gè)用戶:

  • user001: 是一個(gè)普通用戶,只有USER角色;
  • admin: 是一個(gè)管理員用戶,擁有USERADMIN角色。

在上面的代碼中我們還指定了所有訪問都需要認(rèn)真,并且開啟了httpBasic認(rèn)證,通過這個(gè)當(dāng)一個(gè)未認(rèn)證用戶訪問時(shí)就可以通過瀏覽器彈出一個(gè)認(rèn)證對(duì)話框,可以讓用戶輸入用戶名和密碼進(jìn)行認(rèn)證。

2.1.4 實(shí)現(xiàn)應(yīng)用引導(dǎo)類

對(duì)于我們所要實(shí)現(xiàn)的認(rèn)證服務(wù)器來說最重要的就是需要在應(yīng)用引導(dǎo)類中增加@EnableAuthorizationServer注解,通過該注解就可以啟動(dòng)Spring Cloud Security,并且為我們提供一系列端點(diǎn),從而實(shí)現(xiàn)OAuth2.0的認(rèn)證。這些端點(diǎn)分別為:

  • /oauth/authorize: 授權(quán)端點(diǎn);
  • /oauth/token: 獲取訪問令牌端點(diǎn);
  • /oauth/confirm_access: 用戶確認(rèn)授權(quán)提交端點(diǎn);
  • /oauth/error: 認(rèn)證服務(wù)器錯(cuò)誤信息獲取端點(diǎn);
  • /oauth/check_token: 用于資源服務(wù)訪問的令牌解析端點(diǎn);
  • /oauth/token_key: 如果使用JWT令牌,則公開用于令牌驗(yàn)證的公鑰。

2.1.5 實(shí)現(xiàn)用戶信息加載端點(diǎn)

對(duì)于認(rèn)證服務(wù)來說我們還需要提供一個(gè)用戶信息加載端點(diǎn),這樣其它微服務(wù)就可以使用令牌從認(rèn)證服務(wù)器獲取認(rèn)證用戶的信息,從而能夠?qū)崿F(xiàn)用戶認(rèn)證及鑒權(quán)處理。具體實(shí)現(xiàn)代碼如下:

package io.twostepsfromjava.cloud.auth.api;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 獲取當(dāng)前認(rèn)證用戶的信息
 *
 * @author CD826(CD826Dong@gmail.com)
 * @since 1.0.0
 */
@RestController
public class AuthEndpoint {
    protected Logger logger = LoggerFactory.getLogger(AuthEndpoint.class);

    @RequestMapping(value = { "/auth/user" }, produces = "application/json")
    public Map<String, Object> user(OAuth2Authentication user) {
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("user", user.getUserAuthentication().getPrincipal());
        userInfo.put("authorities", AuthorityUtils.authorityListToSet( user.getUserAuthentication().getAuthorities()));
        return userInfo;
    }
}

該段代碼將從Spring Security中獲取到當(dāng)前用戶信息,并轉(zhuǎn)化成一個(gè)Map對(duì)象返回。

2.1.6 編寫配置文件

# 定義應(yīng)用端口
server.port=8290

# 定義應(yīng)用名稱
spring.application.name=authserver

logging.level.org.springframework=INFO
logging.level.io.twostepsfromjava=DEBUG

2.2 完善用戶微服務(wù)

接下來我們將對(duì)用戶微服務(wù)進(jìn)行修改,增加安全處理功能。

2.2.1 引入Security依賴

對(duì)于用戶微服務(wù)來說是一個(gè)Resource server,也就是資源服務(wù)器,當(dāng)訪問到某些資源時(shí)需要進(jìn)行用戶認(rèn)證及鑒權(quán),因此需要引入對(duì)Spring Cloud Security的依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
</dependency>

2.2.2 完善應(yīng)用引導(dǎo)類修改

在Spring Cloud Security中我們只需要對(duì)需要進(jìn)行安全管理的應(yīng)用增加@EnableResourceServer注解來開啟安全管控:

package io.twostepsfromjava.cloud;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

/**
 * TwoStepsFromJava Cloud -- User Service 服務(wù)器
 *
 * @author CD826(CD826Dong@gmail.com)
 * @since 1.0.0
 */
@EnableDiscoveryClient
@EnableResourceServer
@SpringBootApplication
public class Application {

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

}

當(dāng)引入了spring-cloud-security并在應(yīng)用引導(dǎo)類中增加了@EnableResourceServer注解時(shí),應(yīng)用就會(huì)開啟默認(rèn)的安全管控處理,如果你想在自己的應(yīng)用中增加更細(xì)的安全管控,那么需要繼承WebSecurityConfigurerAdapter并實(shí)現(xiàn)安全相關(guān)配置,這個(gè)在這里就不細(xì)講了。

2.2.3 完善應(yīng)用配置

我們需要在應(yīng)用配置文件中增加獲取認(rèn)證用戶信息的端點(diǎn),具體配置如下:

# 保持原來的配置不變

# OAuth2
security.oauth2.resource.user-info-uri=http://localhost:8290/auth/user

所配置的端點(diǎn)也就是之前我們?cè)谡J(rèn)證服務(wù)器所實(shí)現(xiàn)的獲取當(dāng)前登錄用戶信息的端點(diǎn)。

2.2.4 增加獲取當(dāng)前用戶信息的端點(diǎn)

為了進(jìn)行測(cè)試,我們需要在用戶微服務(wù)中增加一個(gè)獲取當(dāng)前已登錄用戶信息的端點(diǎn),代碼如下:

@RequestMapping(value = "/my", method = RequestMethod.GET)
public UserDto myDetail() {
    Map curUser = (Map) SecurityContextHolder.getContext()
            .getAuthentication()
            .getPrincipal();

    String userName = (String)curUser.get("username");
    return new UserDto(userName, userName, "/avatar/default.png", "");
}

這里的代碼非常簡(jiǎn)單,就是直接從SecurityContextHolder中獲取到當(dāng)前已登錄用戶的信息,并構(gòu)造成一個(gè)UserDto,然后返回。

Ok,到此用戶微服務(wù)的改造就完成了。如果你現(xiàn)在啟動(dòng)用戶微服務(wù)并進(jìn)行訪問上面所提供的端點(diǎn),就會(huì)看到如下返回:

未認(rèn)證訪問用戶微服務(wù)

也就是說,現(xiàn)在需要權(quán)限才可以訪問該端點(diǎn)。那么我們?nèi)绾翁峁?quán)限呢?

之前在講OAuth2.0的時(shí)候我們提到客戶端授權(quán)模式有四種,那么我們來看看如何使用這些授權(quán)模式來實(shí)現(xiàn)具體的用戶認(rèn)證處理。

2.3 通過授權(quán)碼模式(authorization code)訪問

首先,讓我們來看看如何通過OAuth2.0所提供的最全面的授權(quán)流程授權(quán)碼模式來實(shí)現(xiàn)用戶認(rèn)證。

我們需要依次啟動(dòng):服務(wù)治理服務(wù)器(Eureak Server)、認(rèn)證服務(wù)器(Auth Server)和用戶微服務(wù)。

第一步,我們首先來構(gòu)造獲取訪問令牌的Url:

http://localhost:8290/oauth/authorize?response_type=code&client_id=malldemo&redirect_uri=http://localhost:8260&scope=webmall&state=63879

對(duì)于該Url說明如下:

  • /oauth/authorize: 這個(gè)是獲取授權(quán)碼的端點(diǎn);
  • client_id: 客戶端的ID,在請(qǐng)求的Url中必選包含。請(qǐng)注意一下我們這里給的值為: malldemo,這個(gè)就是我們?cè)谡J(rèn)證服務(wù)器中配置客戶端列表是所配置的;
  • response_type: 表示授權(quán)類型,也是必選的,對(duì)于授權(quán)碼模式,這里固定填寫為:code;
  • scope: 表示申請(qǐng)的權(quán)限范圍,可以不填。這個(gè)是指當(dāng)有不同的客戶端時(shí)所授權(quán)是否復(fù)用;
  • redirect_uri: 授權(quán)成功后重定向到的URI;
  • state: 表示客戶端的當(dāng)前狀態(tài),可以指定任意值,不論授權(quán)是否成功認(rèn)證服務(wù)器都會(huì)原封不動(dòng)地返回這個(gè)值。

我們,接下來可以直接在瀏覽器中請(qǐng)求這個(gè)地址,然后返回的頁面如下:

用戶登錄截圖

這個(gè)一個(gè)瀏覽器自身的用戶登錄窗口。因?yàn)椋覀儧]有登錄過,所以認(rèn)證服務(wù)器通過httpBasic開啟瀏覽器登錄模式,這樣當(dāng)用戶尚未認(rèn)證時(shí)就會(huì)彈出如上的登錄窗口。

我們?cè)诘卿洿翱谥休斎?code>user001和pwd001也就是之前認(rèn)證服務(wù)器中所配置的用戶列表中的一個(gè),然后就會(huì)跳轉(zhuǎn)到如下頁面:

用戶授權(quán)截圖

這里就是用戶是否授權(quán)的界面。在該界面中我們可以看到所傳入的客戶端應(yīng)用的ID和授權(quán)范圍都會(huì)顯示出來。這里我們點(diǎn)擊【Approve】,然后瀏覽器就會(huì)跳轉(zhuǎn)到redirect_uri所指定的地址,這時(shí)候仔細(xì)觀察所跳轉(zhuǎn)回來的地址,如下:

http://localhost:8260/?code=tn8n8F&state=63879

可以發(fā)現(xiàn)在地址包含了兩個(gè)參數(shù):

  • code: 為認(rèn)證服務(wù)所發(fā)放的授權(quán)碼。該碼的有效期很短,默認(rèn)為10分鐘,并且客戶端只能使用該碼一次,否則會(huì)被認(rèn)證服務(wù)器拒絕。還需要說明一點(diǎn)就是該碼與客戶端ID及重定向URI,是一一對(duì)應(yīng)關(guān)系;
  • state: 這個(gè)就是上面我們請(qǐng)求時(shí)所傳入的參數(shù),認(rèn)證服務(wù)器會(huì)原封不動(dòng)的返回來。

Ok,第一步我們已經(jīng)獲取到了授權(quán)碼。那么第二步就是根據(jù)這個(gè)授權(quán)碼來獲取訪問令牌,在獲取訪問令牌時(shí)我們使用Postman來進(jìn)行,界面截圖如下:

獲取訪問令牌

這該截圖中我們需要填寫以下參數(shù):

  • /oauth/token: 這個(gè)是獲取訪問令牌的端點(diǎn);
  • grant_type: 表示使用的授權(quán)模式,必須填寫,對(duì)于授權(quán)碼模式值固定為"authorization_code";
  • code: 也就是上一步我們所獲得的授權(quán)碼;
  • redirect_uri: 獲取成功后重定向到的URI,同樣我們需要設(shè)置為之前所給的地址;
  • client_id: 客戶端ID,必須填寫,而且需要與之前保持一致。

此外,在上面的截圖中我們還需要填寫授權(quán)認(rèn)證信息,這個(gè)因?yàn)槲覀冋J(rèn)證服務(wù)器開啟了權(quán)限驗(yàn)證,這里填寫客戶端的ID和secret即可。此時(shí)服務(wù)器就會(huì)把客戶端作為一個(gè)用戶來對(duì)待,從而能夠訪問/oauth/token端點(diǎn)。

P.S. 這里這么做主要時(shí)簡(jiǎn)化測(cè)試方法,使得我們上一步訪問時(shí)可以彈出認(rèn)證對(duì)話框。但實(shí)際生產(chǎn)使用時(shí)不應(yīng)這么做,需要自己定義用戶登錄頁面、授權(quán)頁面。

上面的請(qǐng)求,我們可以獲得如下返回:

獲取到訪問令牌

返回的內(nèi)容如下:

  • access_token: 這個(gè)是所獲取訪問令牌;
  • token_type: 令牌類型,Spring Cloud OAuth默認(rèn)返回的值為bearer;
  • expires_in: 表示令牌過期時(shí)間,單位為秒,默認(rèn)為12小時(shí);
  • refresh_token: 更新令牌,過期后可以用來獲取下一次的訪問令牌;
  • scope: 權(quán)限范圍,一般與客戶端申請(qǐng)范圍一致。

有了訪問令牌下一步我就可以訪問用戶微服務(wù)了,訪問方式如下:

通過訪問令牌訪問用戶微服務(wù)

訪問時(shí)我們需要在Header中指定Authorization,并且將值設(shè)置為上一步所獲取到的訪問令牌即可,這樣我們就可以得到正確的數(shù)據(jù)返回了,如上圖所示。

這樣我們就完成了通過授權(quán)碼模式實(shí)現(xiàn)用戶認(rèn)證的測(cè)試。

2.4 通過密碼模式(password)訪問

如果認(rèn)證服務(wù)器是第三方的,那么使用上面的流程問題不大。如果認(rèn)證服務(wù)器是我們自己搭建的,比如該示例,那么上面的授權(quán)顯有點(diǎn)復(fù)雜。接下來讓我們看看如何使用密碼模式來簡(jiǎn)化。

我們按照下圖方式來直接請(qǐng)求認(rèn)證服務(wù)器獲取訪問令牌:

通過密碼獲取用戶授權(quán)-1
通過密碼獲取用戶授權(quán)-2

在上圖中我們需要同時(shí)設(shè)置客戶端的ID、secret及訪問用戶的用戶名和密碼,并將grant_type設(shè)置為password,這樣就可以直接獲取到訪問令牌,如下圖所示:

通過密碼獲取訪問令牌

然后,我們根據(jù)所獲取到的訪問令牌再次訪問用戶微服務(wù),可以獲取如下界面:

訪問用戶微服務(wù)

這說明,用戶認(rèn)證也是成功的。

可見,通過密碼模式可以大大簡(jiǎn)化用戶認(rèn)證流程,但是需要用戶信任客戶端的情況下才會(huì)提供,因此這種方式適合客戶端與認(rèn)證服務(wù)器是同一個(gè)應(yīng)用的情況下。

對(duì)于其它客戶端授權(quán)模式這里就不再一一進(jìn)行測(cè)試了。本文中所提到的示例你可以在這里下載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,785評(píng)論 18 139
  • 1. 微服務(wù)架構(gòu)介紹 1.1 什么是微服務(wù)架構(gòu)? 形像一點(diǎn)來說,微服務(wù)架構(gòu)就像搭積木,每個(gè)微服務(wù)都是一個(gè)零件,并使...
    靜修佛緣閱讀 6,663評(píng)論 0 39
  • 本文目錄:一、單體應(yīng)用 VS 微服務(wù)二、微服務(wù)常見安全認(rèn)證方案三、JWT介紹四、OAuth 2.0 介紹五、思考總...
    挨踢的懶貓閱讀 17,998評(píng)論 5 29
  • 開學(xué)都一個(gè)月了,回去看老師的熱度仍持續(xù)不減。我沒有那個(gè)心思,總覺得過往就應(yīng)該放在那里等著人懷念,揪著不放久了,就跟...
    萌萌噠阿吹閱讀 511評(píng)論 0 0
  • “人一旦有了依賴,就變成了幼兒園里等人來接的小朋友。” 生活中,不管是和家人在一起,還是與朋友相處,都不可避免的會(huì)...
    撒嬌地閱讀 530評(píng)論 0 0