在下游请求中将用户 ID 作为 header 传递。 Spring云网关+Oauth2资源服务器

Pass user id as a header in downstream request. Spring Cloud Gateway + Oauth2 Resource Server

我想通过使我的 Spring 云网关服务器成为 oAuth2 资源服务器来实现安全性。这些请求正在通过我的 spring 安全授权服务器进行身份验证。对于某些请求,我想将经过身份验证的用户的 userId 作为请求 header 传递给我的下游服务。

这是我的路线:

.route("create-deck", routeSpec -> routeSpec
                    .path("/decks")
                    .and()
                    .method(HttpMethod.POST)
                    .filters(
                            fs -> fs.addRequestHeader("userId", "ADD_USER_ID_HEADER_HERE"))
                    .uri("http://localhost:8082/"))

我已将我的授权服务器配置为 return userId 作为主体名称:

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = ur.findByUsername(username);
    if (user == null) {
      log.error("User: {} not found", username);
      throw new UsernameNotFoundException("User: " + username + " not found");
    }

    return new org.springframework.security.core.userdetails.User(String.valueOf(user.getId()), user.getPassword(), authorities);
}

注意:我有一个自定义域 object 用户存储在我的数据库中。

路由已成功通过身份验证,令牌包含 userId 作为主题。我只需要有关如何获取主题并将其作为请求传递给我的下游请求的帮助 header.

我正在使用以下依赖项:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-jose</artifactId>
        <version>5.6.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

您可以创建将应用于所有请求的自定义过滤器。这是一个示例,其中 user 是 jwt 令牌的一部分。

public class UserHeaderFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return ReactiveSecurityContextHolder.getContext()
                .filter(c -> c.getAuthentication() != null)
                .flatMap(c -> {
                    JwtAuthenticationToken jwt = (JwtAuthenticationToken) c.getAuthentication();

                    String user = (String) jwt.getTokenAttributes().get("user");
                    if (Strings.isNullOrEmpty(user)) {
                        return Mono.error(
                                new AccessDeniedException("Invalid token. User is not present in token.")
                        );
                    }

                    ServerHttpRequest request = exchange.getRequest().mutate()
                            .header("x-user", user).build();

                    return chain.filter(exchange.mutate().request(request).build());
                })
                .switchIfEmpty(chain.filter(exchange));
    }
}