如何从 Spring Cloud Gateway 的 GlobalFilter 中的 SecurityContext 获取 BearerTokenAuthentication
Posted
技术标签:
【中文标题】如何从 Spring Cloud Gateway 的 GlobalFilter 中的 SecurityContext 获取 BearerTokenAuthentication【英文标题】:How to get BearerTokenAuthentication from SecurityContext in a GlobalFilter in Spring Cloud Gateway 【发布时间】:2021-07-24 08:36:18 【问题描述】:Spring Cloud Gateway 作为具有以下授权配置的 OAuth2ResourceServer:
@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
http
.authorizeExchange(exchanges ->
exchanges
.anyExchange().authenticated()
)
.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt)
return http.build();
我有一个全局过滤器,负责在每个经过身份验证的有效请求中执行一些功能,如下所示:
@Service
public class CustomGlobal implements GlobalFilter
@Autowired
BearerTokenAuthentication authentication;
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
// access request headers, and perform some logic
// extract details from the JWT token, and perform some logic
log.info(authentication.getTokenAttributes.get("sub"));
// ^ in the above line there's a NullPointerException, since instance
// BearerTokenAuthentication is not set, or not visible at a GlobalFilter class
return chain.filter(exchange);
我仍处于学习阶段。任何可能的线索将不胜感激。
【问题讨论】:
【参考方案1】:我是这样做的(注意你应该将 WebFilter 更改为 GlobalFilter)。
添加到你的 pom 中
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.4.6</version>
</dependency>
那么过滤器应该是这样的
package filter;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Log4j2
public class CustomGlobal implements WebFilter
public static final String HEADER_PREFIX = "Bearer ";
private final ReactiveJwtDecoder jwtDecoder;
public ReactiveJwtDecoder createDecoder(String issuer, String jwkUrl)
var jwtDecoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkUrl).build();
jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
new JwtIssuerValidator(issuer),
new JwtTimestampValidator()));
return jwtDecoder;
protected CustomGlobal(String issuer, String jwkUrl)
this.jwtDecoder = createDecoder(issuer, jwkUrl);
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain)
return Mono
.defer(() ->
var token = resolveToken(exchange.getRequest());
if (!StringUtils.hasText(token))
throw new BadJwtException("Authorisation token is invalid");
return jwtDecoder.decode(token);
)
.flatMap(tokenJwt ->
log.info(tokenJwt.getClaimAsString("sub"));
return chain.filter(exchange);
)
.onErrorResume(err -> handleError(exchange));
private Mono<Void> handleError(ServerWebExchange exchange)
exchange.getResponse().setRawStatusCode(HttpStatus.UNAUTHORIZED.value());
exchange.getResponse().getHeaders().add("Content-Type", "application/json");
return exchange.getResponse().setComplete();
private String resolveToken(ServerHttpRequest request)
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(HEADER_PREFIX))
return bearerToken.substring(7).trim();
return "";
下一步是创建配置
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@Configuration
public class CustomGlobalConfig
@Value("$jwt.iss")
private String issuer;
@Value("$jwt.jwk-uri")
private String jwkUrl;
@Bean
CustomGlobal createFilterBean()
return new CustomGlobal(this.issuer, this.jwkUrl);
【讨论】:
以上是关于如何从 Spring Cloud Gateway 的 GlobalFilter 中的 SecurityContext 获取 BearerTokenAuthentication的主要内容,如果未能解决你的问题,请参考以下文章
服务门户:Spring Cloud Gateway 如何把好微服务的大门
从 Spring Cloud Gateway 到底层服务的凭证传播
如何配置 spring-cloud-gateway 以使用 sleuth 记录请求/响应正文
如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url