spring - 需要从 Spring Cloud Gateway 路由中的 OAuth2User 获取经过身份验证的用户名
问题描述
我是 Spring Cloud Gateway 的新手。我创建了一个简单的 SCG 应用程序,我的用例是通过 http 请求标头将经过身份验证的用户名转发到我的下游应用程序。
这是我的 SpringBoot 类
package com.xyz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties.Jwt;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
@SpringBootApplication
public class OracleSSOMultiplexer {
@Autowired
private TokenRelayGatewayFilterFactory filterFactory;
@GetMapping("/")
public String index(Model model,
@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
@AuthenticationPrincipal OAuth2User oauth2User) {
model.addAttribute("userName", oauth2User.getName());
model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());
model.addAttribute("userAttributes", oauth2User.getAttributes());
return "index";
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
//.route("resource", r -> r.path("/resource")
.route(r -> r.path("/hyperion/**")
.filters(f -> f.filters(filterFactory.apply())
.addRequestHeader("HYPLOGIN", "scott") // I need to pass the authenticated username here instead of hardcoding it
.addResponseHeader("hyp-response", "hyp-response-header-val"))
.uri("http://localhost:8081/")
.id("hyperionModule"))
.build();
}
public static void main(String[] args) {
SpringApplication.run(OracleSSOMultiplexer.class, args);
}
}
这是我的 application.yml
server:
port: 8080
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.web.HttpLogging: DEBUG
org.springframework.security: DEBUG
org.springframework.security.oauth2: DEBUG
org.springframework.cloud.gateway: DEBUG
spring:
autoconfigure:
# TODO: remove when fixed https://github.com/spring-projects/spring-security/issues/6314
exclude: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
thymeleaf:
cache: false
security:
oauth2:
client:
registration:
gateway:
provider: pingfederate
client-id: oidchyperion
client-secret: Lms@12345
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8080/login/oauth2/code/gateway
scope: openid
provider:
pingfederate:
authorization-uri: https://xyz:9035/as/authorization.oauth2
token-uri: https://xyz:9035/as/token.oauth2
user-info-uri: https://xyz:9035/idp/userinfo.openid
user-name-attribute: sub
jwk-set-uri: https://xyz:9035/pf/JWKS
# cloud:
# gateway:
# routes:
# - id: resource
# uri: http://resource:9000
# predicates:
# - Path=/resource
# filters:
# - TokenRelay=
# - RemoveRequestHeader=Cookie
我能够执行 OAuth 身份验证,并能够使用 index.html 中的模型显示经过身份验证的用户信息。我现在只需要在请求标头中传递登录用户的用户名(oauth2user.getName()),但我无法弄清楚。
感谢您在这方面提供任何帮助。
谢谢, 塔尼
解决方案
package com.likeminds.filter;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
@Component
public class AuthNUserHeaderFilterFactory extends
AbstractGatewayFilterFactory<AuthNUserHeaderFilterFactory.Config> {
private static final String VALUE = "value";
public AuthNUserHeaderFilterFactory() {
super(Config.class);
}
@Override
public Config newConfig() {
return new Config();
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList(VALUE);
}
@Override
public GatewayFilter apply(Config config) {
//Custom Pre Filter. Suppose we can extract JWT and perform
Authentication
return (exchange, chain) -> exchange.getPrincipal()
.map(Principal::getName)
.defaultIfEmpty("Default User")
.map(userName -> {
//adds header to proxied request
System.out.println("Config value ="+config.value);
exchange.getRequest().mutate().header(config.value,
userName).build();
System.out.println("Config First pre header filter" +
exchange.getRequest().getHeaders());
return exchange;
})
.flatMap(chain::filter);
}
public static class Config {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
推荐阅读
- ios - Flutter,无法为 iOS 构建:缺少 .h 文件
- android - 在 ScrollView 内的 Textview 中复制文本
- html - 如何在另一个 div 中的两个 div 之间插入一些水平空间?
- html - 如何修复导航栏上的悬停下拉菜单?
- python - sklearn.preprocessing.MinMaxScaler:不可广播的输出形状错误
- python - Python Loop 超出范围
- ios - 从 iOS 通知中获取有效负载数据的问题
- javascript - 如何在 google-libphonenumber Js 包中获取 ISO 国家代码
- amazon-web-services - Lambda 在超时时向 API 网关返回 Http 200
- javascript - 使用 nodejs 本机驱动程序从两个不同的客户端更新 MongoDB 文档