【问题标题】:How to get BearerTokenAuthentication from SecurityContext in a GlobalFilter in Spring Cloud Gateway如何从 Spring Cloud Gateway 的 GlobalFilter 中的 SecurityContext 获取 BearerTokenAuthentication
【发布时间】: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);
    }
}

我仍处于学习阶段。任何可能的线索将不胜感激。

【问题讨论】:

    标签: spring spring-security spring-webflux spring-cloud-gateway


    【解决方案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);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-10
      • 2016-12-10
      • 2022-10-20
      • 2018-12-18
      • 2020-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多