請求轉發
Spring Cloud Gateway 可以通過代碼或者配置文件指定路由,我還是習慣在配置文件里面操作。這里簡單配置將所有/api/**
的請求都轉發到 api-service 進行處理。
spring:
cloud.gateway.routes:
- id: api-service-route
uri: http://localhost:8080
predicates:
- Path=/api/**
filters:
- StripPrefix=1這個例子中,如果訪問
http://localhost:8082/api/hello
,gateway-service 會把對應的請求轉到http://localhost:8080/hello
,實際進行處理的是 api-service。StripPrefix 是 Spring Cloud Gateway 提供的 Gateway Filter,Spring Cloud Gateway 提供了眾多預設的 Filters,你可以在 Spring Cloud Gateway 官方文檔 中進行查詢,可以根據自己的需求使用已有的 Filters 進行快速開發,當然也可以參考這些 Filters 的源碼
自己封裝自定義的 Filter。
負載均衡
我們的后端服務通常是需要實現高可用的,將 user-service 和 gateway-service 注冊到注冊中心(我們使用 Consul),spring.cloud.gateway.discovery.locator.enabled = true
啟用服務發現,並搭配 lb://
使用負載均衡(load balancer)。在 Spring Cloud Gateway 中,LoadBalancerClientFilter
負責處理 lb 請求並獲取到真實請求地址。
spring.cloud.gateway:
discovery.locator.enabled: true
routes:
- id: api-service-route
uri: lb://api-service
predicates:
- Path=/api/**
filters:
- StripPrefix=1
身份認證
認證中心是基於 Spring Security 實現標准 OAuth2.0 認證服務,我們依然使用
spring-security-oauth2-resource-server
將 Gateway 作為 oauth2 client 進行集成。
用戶的訪問基本上都是需要攜帶 JWT Token 的,gateway-service 在接收到請求之后,會向鑒權服務發送鑒權請求,獲得授權之后可以得到當前訪問的用戶詳細信息;如果檢測到請求未
經授權,那么 gateway-service 直接會返回未授權錯誤,保護內部服務訪問安全。
理論上鑒權也可以通過自定義 gateway filter 來實現,不過我們希望可以盡可能多使用 spring-security
提供的能力,畢竟自己封裝需要實現的東西還是有點多的。
Spring Cloud Gateway 只支持搭配 webflux 使用,所以我們后續使用了 @EnableWebFluxSecurity
注解。
我們將 gateway 作為一個 resource server 進行配置,畢竟 spring-security
幫我們做了很多事情,所以需要我們自己配置的代碼很少。
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated();
http.oauth2ResourceServer().jwt();
return http.build();
}
因為我們的 authorization server 使用了 jwt token,jwt 很適合在純 RESTful API 中作為無狀態的認證憑證進行使用,搭配 spring security oauth2 的話,簡單且好用。當然如果在某些場景下需要撤銷某個 jwt token,也可以搭配 redis 進行管理。
我們在上面代碼中聲明了 gateway-service 作為一個簡單的 resource server 並啟用了 jwt,jwt token 通過公鑰來驗證有效性。因此我們需要指定 jwt 鑒權的公鑰地址。
spring.security.oauth2.resourceserver.jwt:
jwk-set-uri: 'http://localhost:8081/.well-known/jwks.json'
經過上面這些配置之后,我們就已經實現了一個比較簡單的微服務架構下的網關服務了。