Spring Cloud GatewayカスタムTokenチェックフィルタ
12808 ワード
すべてのビジネス開発はニーズに基づいています.まず、ニーズを見てみましょう.
アクセスゲートウェイの要求に対してtoken検証を行い、token検証が通過した場合にのみバックエンドサービスに転送され、そうでなければ直接401に戻る
本明細書で説明するコードの例は、シーンに適用されます.
tokenはredisに格納され、keyはユーザのuidである
依存pom.xml
Spring Cloud Gatewayでは、主にGlobalFilterとGatewayFilterの2種類のフィルタがあります. GlobalFilter:グローバルフィルタ、すべてのルーティングに対して GatewayFilter:指定されたルーティングにのみ機能する 1、カスタムGatewayFilter
カスタムGatewayFilterには、GatewayFilterインタフェースを直接実装する方法と、AbstractGatewayFilterFactoryクラスを継承する方法の2つがあります.
1.1 GatewayFilterインタフェースの実装
まずヘッダヘッダ情報からuidとtoken情報を取得し、tokenまたはuidがnullの場合、要求パラメータから再取得を試み、tokenまたはuidが依然として存在しない場合、直接401状態に戻り、同時に要求を終了する.両方が存在する場合、保存authTokenがuidに従ってredisから読み出され、要求で送信tokenと比較する、比較するようにフィルタチェーンを通過し続ける、そうでなければ直接要求を終了し、401に戻る.
AuthorizeGatewayFilterをどのように適用しますか?
1.2 AbstractGatewayFilterFactoryクラスの継承
AuthorizeGatewayFilterFactoryをどのように適用しますか?
上記の2つの方式はいずれもアクセスゲートウェイの特定の要求に対してtoken検証を実現することができ、すべての要求に対してtoken検証を行う場合はGlobalFilter方式を実現することができる.
2、カスタムGlobalFilter
AuthorizeFilterをどのように適用しますか?
追加するだけ
@Component注記、追加の構成を必要とせず、GlobalFilterインタフェースを実現し、すべてのルーティングに自動的に役立ちます.
3、まとめ
Spring Cloud Gatewayに触れたばかりなので、あまり詳しくないところもありますが、上記のサンプルコードは参考にしているだけなので、間違ったところがあれば、指摘してください.
コメント:上記のコードを実行するには、redisサービスを開始する必要があります.redisのアドレスとポートが構成されていないため、デフォルトではlocalhostと6379ポートが採用されています.一致しない場合は、自分でアプリケーションを使用してください.ymlファイルで構成すればいいです. ゲートウェイのポートはデフォルトの8080を採用しています. ゲートウェイを介して/user/listにアクセスするとtoken検証が通過すると、http://localhost:8077/api/user/list上、これは別のインタフェースサービスで、自分で実際の状況に応じて修正します.
参考学習: Spring Cloud Gateway公式ドキュメント Spring Cloud Gatewayソースコード
アクセスゲートウェイの要求に対してtoken検証を行い、token検証が通過した場合にのみバックエンドサービスに転送され、そうでなければ直接401に戻る
本明細書で説明するコードの例は、シーンに適用されます.
tokenはredisに格納され、keyはユーザのuidである
依存pom.xml
4.0.0
com.winture
api-gateway
0.0.1-SNAPSHOT
jar
api-gateway
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
Finchley.SR1
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
Spring Cloud Gatewayでは、主にGlobalFilterとGatewayFilterの2種類のフィルタがあります.
カスタムGatewayFilterには、GatewayFilterインタフェースを直接実装する方法と、AbstractGatewayFilterFactoryクラスを継承する方法の2つがあります.
1.1 GatewayFilterインタフェースの実装
package com.winture.gateway.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* token
* @Version V1.0
*/
public class AuthorizeGatewayFilter implements GatewayFilter, Ordered {
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
まずヘッダヘッダ情報からuidとtoken情報を取得し、tokenまたはuidがnullの場合、要求パラメータから再取得を試み、tokenまたはuidが依然として存在しない場合、直接401状態に戻り、同時に要求を終了する.両方が存在する場合、保存authTokenがuidに従ってredisから読み出され、要求で送信tokenと比較する、比較するようにフィルタチェーンを通過し続ける、そうでなければ直接要求を終了し、401に戻る.
AuthorizeGatewayFilterをどのように適用しますか?
package com.winture.gateway;
import com.winture.gateway.filter.AuthorizeGatewayFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r ->
r.path("/user/list")
.uri("http://localhost:8077/api/user/list")
.filters(new AuthorizeGatewayFilter())
.id("user-service"))
.build();
}
}
1.2 AbstractGatewayFilterFactoryクラスの継承
package com.winture.gateway.filter.factory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory {
private static final Log logger = LogFactory.getLog(AuthorizeGatewayFilterFactory.class);
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
public AuthorizeGatewayFilterFactory() {
super(Config.class);
logger.info("Loaded GatewayFilterFactory [Authorize]");
}
@Override
public List shortcutFieldOrder() {
return Arrays.asList("enabled");
}
@Override
public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) {
return (exchange, chain) -> {
if (!config.isEnabled()) {
return chain.filter(exchange);
}
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
};
}
public static class Config {
//
private boolean enabled;
public Config() {}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}
AuthorizeGatewayFilterFactoryをどのように適用しますか?
#
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8077/api/user/list
predicates:
- Path=/user/list
filters:
# , true ,false
# spring cloud gateway GatewayFilterFactory
- Authorize=true
上記の2つの方式はいずれもアクセスゲートウェイの特定の要求に対してtoken検証を実現することができ、すべての要求に対してtoken検証を行う場合はGlobalFilter方式を実現することができる.
2、カスタムGlobalFilter
package com.winture.gateway.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* token
* @Version V1.0
*/
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
AuthorizeFilterをどのように適用しますか?
追加するだけ
@Component注記、追加の構成を必要とせず、GlobalFilterインタフェースを実現し、すべてのルーティングに自動的に役立ちます.
3、まとめ
Spring Cloud Gatewayに触れたばかりなので、あまり詳しくないところもありますが、上記のサンプルコードは参考にしているだけなので、間違ったところがあれば、指摘してください.
コメント:
参考学習: