1. 概述
本教程將介紹 Spring Security 中的 <em @EnableResourceServer</em> 和 <em @EnableOAuth2Sso</em> 註解。
我們將首先解釋 OAuth2 客户端 和 OAuth2 資源服務器 之間的差異。之後,我們將討論這些註解能為我們做什麼,並使用一個示例演示其用法,該示例使用了 Zuul 和一個簡單的 API。
為了本文的目的,我們假設您已經具備了對 Zuul 和 OAuth2 的一定經驗。
如果您沒有相關經驗,或者認為對其中任何一個進行回顧會有所幫助,請參考我們關於 Zuul 的快速概述以及關於 OAuth2 的指南。
2. OAuth2 客户端和資源服務器
OAuth2 中需要考慮的四種不同角色是:
- 資源擁有者— 能夠授權其受保護資源的實體
- 授權服務器— 向 客户端 授予訪問權限,在成功驗證 資源擁有者 並獲得其授權後
- 資源服務器— 一個需要訪問令牌才能允許訪問其資源的組件
- 客户端— 能夠從授權服務器獲取訪問令牌的實體
使用 @EnableResourceServer 或 @EnableOAuth2Sso 註解來標註我們的配置類,會指示 Spring 配置組件,將我們的應用程序轉換為上述兩種角色之一。
@EnableResourceServer 註解使我們的應用程序以 資源服務器 的身份運行,通過配置 OAuth2AuthenticationProcessingFilter 以及其他同樣重要的組件。
查閲 ResourceServerSecurityConfigurer 類,可以更好地瞭解幕後配置的內容。
相反, @EnableOAuth2Sso 註解將我們的應用程序轉換為 OAuth2 客户端。它指示 Spring 配置 OAuth2ClientAuthenticationProcessingFilter 以及我們的應用程序需要具備從授權服務器獲取訪問令牌的其他組件。
查閲 SsoSecurityConfigurer 類,可以獲得更多關於 Spring 配置的內容。
結合這些註解和一些屬性,可以快速啓動應用程序。讓我們創建兩個不同的應用程序,以查看它們在行動中的效果以及它們如何互補:
- 我們的第一個應用程序將是我們的邊緣節點,一個簡單的 Zuul 應用程序,它將使用 @EnableOAuth2Sso 註解。它將負責驗證用户(藉助 授權服務器)並將傳入請求委派給其他應用程序
- 第二個應用程序將使用 @EnableResourceServer 註解,並允許如果傳入請求包含有效的 OAuth2 訪問令牌,則訪問受保護的資源
3. Zuul – @EnableOAuth2Sso
讓我們首先創建一個 Zuul 應用程序,它將作為我們的邊緣節點,並負責使用 OAuth2 Authorization Server 來認證用户:
@Configuration
@EnableZuulProxy
@EnableOAuth2Sso
@Order(value = 0)
public class AppConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ResourceServerTokenServices
resourceServerTokenServices;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authorization-server-1/**",
"/login").permitAll()
.anyRequest().authenticated().and()
.logout().permitAll().logoutSuccessUrl("/");
}
}對我們的 Zuul 應用程序進行註釋,使用 @EnableOAuth2Sso 還會通知 Spring 配置一個 OAuth2TokenRelayFilter 過濾器。該過濾器從用户的 HTTP 會話中檢索先前獲取的訪問令牌,並將其向下傳遞。
請注意,我們還在我們的 AppConfiguration 配置類中使用 @Order 註解。這是為了確保由我們的 WebSecurityConfigurerAdapter 創建的過濾器優先於由其他 WebSecurityConfigurerAdapters 創建的過濾器。
例如,我們可以使用 @EnableResourceServer 註解來支持我們的 Zuul 應用程序,以支持 HTTP 會話標識符和 OAuth2 訪問令牌。但是,這樣做會創建新的 Filters,這些過濾器默認情況下優先於由 AppConfiguration 類創建的過濾器。這是因為 ResourceServerConfiguration,一個由 @EnableResourceServer 觸發的配置類,指定了一個默認的 order 為 3,而 WebSecurityConfigureAdapter 具有默認的 order 為 100。
在我們轉向我們的 Resource Server 之前,我們需要配置一些屬性:
zuul:
routes:
resource-server-mvc-1: /resource-server-mvc-1/**
authorization-server-1:
sensitiveHeaders: Authorization
path: /authorization-server-1/**
stripPrefix: false
add-proxy-headers: true
security:
basic:
enabled: false
oauth2:
sso:
loginPath: /login
client:
accessTokenUri: http://localhost:8769/authorization-server-1/oauth/token
userAuthorizationUri: /authorization-server-1/oauth/authorize
clientId: fooClient
clientSecret: fooSecret
resource:
jwt:
keyValue: "abc"
id: fooScope
serviceId: ${PREFIX:}resource不 вдаваясь в подробности, используя эту конфигурацию, мы:
- Настраиваем наши маршруты Zuul и указываем, какие заголовки следует добавить/удалить перед отправкой запросов в другие системы.
- Устанавливаем некоторые свойства OAuth2 для нашего приложения, чтобы оно могло взаимодействовать с нашим Authorization Server и настраиваем JWT с симметричным шифрованием.
4. API – <em @EnableResourceServer>
現在我們已經部署了我們的 Zuul 應用程序,接下來我們創建我們的 資源服務器:
@SpringBootApplication
@EnableResourceServer
@Controller
@RequestMapping("/")
class ResourceServerApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceServerApplication.class, args);
}
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public String helloWorld(Principal principal) {
return "Hello " + principal.getName();
}
}這是一個簡單的應用程序,它暴露了一個單一端點,以返回發起請求的Principal的名稱。
我們來總結一下,通過配置一些屬性:
security:
basic:
enabled: false
oauth2:
resource:
jwt:
keyValue: "abc"
id: fooScope
service-id: ${PREFIX:}resource請注意,我們需要一個有效的訪問令牌(它存儲在我們的邊緣節點用户的 HTTP 會話中)才能訪問我們的 資源服務器的端點。
5. 結論
在本文中,我們解釋了<em @EnableOAuth2Sso</em>和<em @EnableResourceServer</em>這兩個註解之間的差異。我們還通過一個實際示例,使用<em Zuul</em>和簡單的API來演示瞭如何使用它們。
當本地運行應用程序時,我們可以通過以下地址運行和測試應用程序:<em http://192.168.1.67:8765/resource-server-mvc-1</em>。