spring security 實戰 6-使用客戶端模式(Client Credentials grant)保護資源

寫在開篇

本改編課程基於《OAuth 2.0 Cookbook_Protect Your Web Applications using Spring Security-Packt Publishing(2017)》。這本書側重經過一個個精簡的小例子來學習,如何使用spring security和oauth2.0來保護你的資源。java

課程從第二章開始,在Chaptor2,咱們將學習如下內容:web

  1. 使用受權碼模式(Authorization Code grant)保護資源
  2. 支持隱式受權模式(Implicit grant)
  3. 使用密碼模式(Resource Owner Password Credentials grant type )
  4. 配置客戶端證書受權模式(Client Credentials grant)
  5. 支持refresh tokens
  6. 使用一個關係數據庫來保存tokens和客戶信息
  7. 使用redis保存token
  8. 實現客戶端註冊過程
  9. 中途破壞Oauth 2.0 Provider
  10. 使用Gatling,經過共享數據庫測試token的驗證過程

本例將講解如何配置客戶端模式,當一個應用本身自己須要獲取資源(無需用戶受權),而不是獲取資源全部者的資源時,客戶端模式十分有用。redis

Getting Ready

Java8 + mavenspring

本文源碼可點擊下載數據庫

How to do it…

下面的步驟將指導你如何使用spring security OAuth2.0 配置一個受權中心和一個資源服務器:json

  1. 使用Spring Initializr 新建一個Springboot工程,加入web,security依賴。
  2. 打開pom.xml,加入如下依賴:
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId> 
</dependency>

1.打開application.properties文件,輸入:segmentfault

security.user.name=adolfo

security.user.password=123api

2.儘管本例不關注於用戶行爲,咱們依然須要建立一個API來獲取用戶的profile。爲了保證用戶能夠經過應用程序以一種安全的方式獲取profile,新建UserProfileUserController類,內容和《學習3》同樣。安全

3.打開UserController,將@RequestMapping的註解由「/api/profile」改成"/user"服務器

4.因爲咱們在使用客戶端模式,咱們將不容許客戶端獲取用戶的profile。咱們能夠建立一個API,來讓客戶端能夠獲取在本服務器註冊的用戶信息。可能這種模式對你而言沒啥意義,如今咱們將目光移到如何使用客戶端模式,而不是它對你有沒有用。好了,咱們來建立AdminController,一下是這個類的具體實現:

@Controller 
@RequestMapping("/api") 
public class AdminController {
    @RequestMapping("/users") 
    public ResponseEntity<List<UserProfile>> getAllUsers() { 
        return ResponseEntity.ok(getUsers()); 
    } 
    
    private List<UserProfile> getUsers() { 
        List<UserProfile> users = new ArrayList<>(); 
        users.add(new UserProfile("adolfo", "adolfo@mailinator.com")); 
        users.add(new UserProfile("demigreite", "demigreite@mailinator.com")); 
        users.add(new UserProfile("jujuba", "jujuba@mailinator.com")); 
        return users; 
    } 
}

4.爲了保護這個API,咱們來建立一個資源服務配置類:

@Configuration 
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter { 
    @Override 
    public void configure(HttpSecurity http) throws Exception { 
        http.authorizeRequests().anyRequest().authenticated() 
            .and() 
            .requestMatchers().antMatchers("/api/**"); 
    } 
}

5.爲了頒發access token,咱們須要建立一個受權中心,注意如今咱們定義了一個不一樣的client ID和密碼,還有不一樣的authorizedGrantTypes:

@Configuration
@EnableAuthorizationServer 
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter { 
    @Override 
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
        clients.inMemory() 
            .withClient("clientadmin") 
            .secret("123") 
            .authorizedGrantTypes("client_credentials") 
            .scopes("admin"); 
    } 
}

6.如今咱們要保護/users API,也就是一批沒有在客戶端註冊的用戶信息:

@Configuration
@EnableWebSecurity 
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and() 
            .antMatcher("/user/**").httpBasic() 
            .and() 
            .csrf().disable();
    } 
}

如今所有配好了

How it works…

本例展現了OAuth2.0一種特殊模式,讓註冊的客戶端直接訪問資源。以前的幾種模式均是經過依賴用戶的批准,第三方客戶端才能訪問資源。由於本例的特殊性,咱們專門新建了一個api,可讓客戶端拿到全部註冊在OAuth2.0 Provider上的用戶。

受權中心和資源服務中心的配置和前幾種模式幾乎一致,最大的不一樣就是咱們不須要重定向地址,此外,咱們也要將驗證模式改一下。就像這樣的

clients.inMemory()
    .withClient("clientadmin")
    .secret("123")
    .authorizedGrantTypes("client_credentials")
    .accessTokenValiditySeconds(120)
    .scopes("admin");

如今咱們來啓動服務,看看程序是如何與Oauth 2.0 Provider進行交互。當咱們使用客戶端模式的時候,咱們並無任何用戶的交互,因此也沒有受權的模塊。可是咱們仍是須要申請一個受權碼:

咱們能夠經過curl

curl -X POST " http://localhost:8080/oauth/t..." --user clientadmin:123 -d "grant_type=client_credentials&scope=admin"

或者PostMan
圖片描述

發送請求後,你會獲得以下的回覆:

{
    "access_token": "22924299-e715-4d7d-a30b-4d315aa932a3",
    "token_type": "bearer",
    "expires_in": 56,
    "scope": "admin"
}

須要注意的是,使用客戶端模式的時候,根據OAUTH2.0規範,不該該頒發refreshed token。由於使用客戶端模式,不用考慮用戶體檢,客戶端自身能夠在access token過時的時候從新申請新的access token。

如今咱們能夠攜帶access token去拿去資源了,可能你已經意識到,當咱們拿到access token後,咱們就能夠獲取資源,而無關咱們使用什麼途徑拿到這個資源的。

curl " http://localhost:8080/api/users" -H "Authorization: Bearer f6f81a52-7920-4f95-a83b-72fbfb5188c5"

或者:
圖片描述

本例向你展現瞭如何使用客戶端模式來保護資源,同時你還能夠選擇其餘的模式(例如HTTP Basic Authentication)保護資源。咱們以前在第9步時,配置了WebSecurityConfiguration,其中

.antMatcher("/user/**").httpBasic()

說明匹配的endpoint將使用http 基礎認證。所以,咱們沒法經過以前的方法拿到/user 對應的資源,可是,咱們能夠經過如下辦法獲取:

curl "<http://localhost:8080/user>" --user adolfo:123

或者:
圖片描述

There's more…

客戶端模式是客戶端自己請求驗證的行爲,因此無需用戶「認證」,不牽涉任何用戶的行爲。可是如今的微服務體系不怎麼使用這種模式,由於這種模式能夠輕易地經過refresh token來不斷獲取access token,而且也可使用動態的註冊流程,在集成服務時自動執行全部流程。

考慮到不少微服務都是基於這種模式來溝通,所以存在大量的access token驗證過程。基於這種狀況,咱們須要考慮驗證策略,不一樣的策略會不一樣程度地影響服務器的性能。在本週的最後章節,咱們將學到,如何建立負載測試應用程序,和如何使用Gatling測量驗證訪問令牌時的響應時間。

相關文章
相關標籤/搜索