1. 程式人生 > >Spring Cloud 安全:整合OAuth2實現身份認證和單點登入

Spring Cloud 安全:整合OAuth2實現身份認證和單點登入

1、概述

Spring Cloud 的安全模組可以為Spring Boot應用提供基於令牌的安全特性。具體講就是支援OAuth2協議來實現單點登入(SSO),可以很方便地在資源服務之間傳遞身份令牌,以及使用嵌入式的ZUUL代理來配置下游服務的認證。

在這篇文章中,我們將介紹如何在Spring Boot 客戶端應用、身份認證服務與提供REST API的資源服務之間配置完成這些功能。實現系統的安全訪問控制、身份認證和單點登入。

在這個例子中,我們使用了2個客戶端應用程式來演示雲安全特性中的SSO,只不過這2個應用是一樣的。

2、建立雲安全應用

首先在所有Spring Boot應用中配置SSO,需要增加spring-cloud-starter-oauth2依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>1.2.2.RELEASE</version>
</dependency>

它會自動包含spring-cloud-starter-security依賴。

由於有多個客戶端來連線Spring OAuth2 Auth Server,需要在配置類裡為inMemory生成器定義多個withClients。

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("first").secret("passwordforauthserver")
                .redirectUris("http://localhost:8080/").authorizedGrantTypes("authorization_code", "refresh_token"
) .scopes("myscope").autoApprove(true).accessTokenValiditySeconds(30).refreshTokenValiditySeconds(1800) .and() .withClient("second").secret("passwordforauthserver") .redirectUris("http://localhost:8081/").authorizedGrantTypes("authorization_code", "refresh_token") .scopes("myscope").autoApprove(true).accessTokenValiditySeconds(30).refreshTokenValiditySeconds(1800); }

另外需要配置一個資源服務,代表受保護的服務。服務埠為9000。

提供REST服務介面供客戶端呼叫。

@RestController
public class PersonInfoController {

    @GetMapping("/person")
    @PreAuthorize("hasAnyRole('ADMIN', 'USER')")
    public @ResponseBody Person personInfo() {
        return new Person("peter", "Beijing", "China", 29, "Male");
    }   
}

同時提供一個/usr介面供客戶端來獲得使用者的憑證。

@RestController
public class ResourceController {

    @RequestMapping("/user")
    public Principal user(Principal user) {
      return user;
    }

}

最後是客戶端應用,在配置類裡增加安全註解:

@Configuration
@EnableOAuth2Sso
public class SiteSecurityConfigurer
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // ...    
    }
}

任何需要身份驗證的請求都將被重定向到授權伺服器。為此,我們還必須定義伺服器屬性:

security:
  oauth2:
    client:
      accessTokenUri: http://localhost:7070/authserver/oauth/token
      userAuthorizationUri: http://localhost:7070/authserver/oauth/authorize
      clientId: first
      clientSecret: passwordforauthserver
    resource:
      userInfoUri: http://localhost:9000/user

3、傳遞令牌

當傳遞令牌時,OAuth2客戶端將其接收到的OAuth2令牌轉發給資源服務。由於我們已經聲明瞭@EnableOauth2Sso註解,Spring Boot 會在請求上下文中新增一個OAuth2ClientContext物件,因此我們可以在客戶端應用程式中建立自己的OAuth2RestTemplate。

@Bean
public OAuth2RestOperations restOperations(
  OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {
    return new OAuth2RestTemplate(resource, context);
}

一旦我們配置了這個Bean,上下文就會將訪問令牌轉發給所請求的服務,並且如果令牌到期了也將會重新整理令牌。

4、使用RestTemplate傳遞OAuth令牌

之前我們在客戶端應用程式中定義了一個OAuth2RestTemplate 型別的restOperations bean。因此可以使用OAuth2RestTemplate中的getForObject() 方法來發送帶有令牌的請求到受保護的資源服務。

@Autowired
private RestOperations restOperations;

@GetMapping("/personInfo")
public ModelAndView person() { 
    ModelAndView mav = new ModelAndView("personinfo");
    String personResourceUrl = "http://localhost:9000/person";
    mav.addObject("person", 
      restOperations.getForObject(personResourceUrl, String.class));       

    return mav;
}

5、配置Zuul傳遞令牌

如果我們想把一個令牌轉發給代理服務,我們可以使用Spring Cloud Zuul嵌入式反向代理。

在客戶端應用中引入Zuul依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

然後在配置類裡新增@EnableZuulProxy 註解

@Configuration
@EnableOAuth2Sso
@EnableZuulProxy
public class SiteSecurityConfigurer
  extends WebSecurityConfigurerAdapter {
    //...
}

同時在application.yml 檔案裡新增Zuul的配置項

zuul:
  routes:
    resource:
      path: /api/**
      url: http://localhost:9000
    user: 
      path: /user/**
      url: http://localhost:9000/user

這樣任何訪問客戶端應用/api端點的請求被重定向到資源服務的URL。這些請求都會帶著OAuth令牌。

6、執行效果

直接訪問受保護的資源服務,顯示未認證
這裡寫圖片描述

輸入使用者名稱、密碼(user/user),顯示資源服務資料
這裡寫圖片描述

通過Zuul代理訪問資源服務
這裡寫圖片描述

7、總結

在這篇文章裡,我們討論瞭如何使用Spring Cloud Security的OAuth2和Zuul來配置安全的認證服務和資源服務,以及使用Oauth2RestTemplate和嵌入的Zuul代理在服務之間傳遞OAuth2令牌。示例程式碼下載地址