[英]Using Auth0 in Spring Cloud Gateway, problem with getting ID Token
We have problems with obtaining ID token using auth0 SDK. We have API Gateway based on Spring Cloud Gateway (version 3.1.4) where we try to use your auth0 platform to authenticate the users and then route the exchange to our micro services.我们在使用 auth0 SDK 获取 ID 令牌时遇到问题。我们有基于 Spring 云网关(版本 3.1.4)的 API 网关,我们尝试使用您的 auth0 平台对用户进行身份验证,然后将交换路由到我们的微服务。 To do it we would like to use ID Token and get email from it and pass this email to our micro services.
为此,我们想使用 ID Token 并从中获取 email 并将此 email 传递给我们的微服务。 We log in by hitting
oauth2/authorization/auth0
endpoint, we are being redirected to auth0 login page, where we provide credentials, then we get redirect back to our app.我们通过点击
oauth2/authorization/auth0
端点登录,我们被重定向到 auth0 登录页面,我们在其中提供凭据,然后我们被重定向回我们的应用程序。
When we configuire endpoints directly in API Gateway and mark them with @AuthenticationPrincipal OidcUser user
it works and we have full user details as well as ID token.当我们直接在 API 网关中配置端点并用
@AuthenticationPrincipal OidcUser user
标记它们时,它可以工作,我们有完整的用户详细信息以及 ID 令牌。 When we proxy the exchange to different service we have Authorisation header in the request, which contains only header & signature part without payload in the ID token.当我们将交换代理到不同的服务时,我们在请求中有授权 header,它仅包含 header 和 ID 令牌中没有有效负载的签名部分。
We would need the payload in ID Token in order to fetch user email for mapping the user with our internal DB in our micro services.我们需要 ID Token 中的有效负载才能获取用户 email,以便将用户映射到我们微服务中的内部数据库。
What do you think would be the proper workflow in this case and how can we solve this issue?在这种情况下,您认为正确的工作流程是什么?我们如何解决这个问题?
We tried to use Rules & Actions, which I paste below, but it didn't helped us.我们尝试使用我在下面粘贴的规则和操作,但它对我们没有帮助。
Our configuration looks like this:我们的配置如下所示:
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) throws Exception {
return http
.csrf().disable()
.authorizeExchange()
.pathMatchers("/test").authenticated()
.anyExchange().authenticated()
.and().oauth2Login()
.and().logout().logoutSuccessHandler(logoutSuccessHandler())
.and().build();
}
In the RouteLocator in GatewayConfiguration we have filter for TokenRelay.在 GatewayConfiguration 的 RouteLocator 中,我们有 TokenRelay 过滤器。
Our Action looks like this:我们的行动看起来像这样:
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'http://test.{our_local_development_route}:8888';
if (event.authorization) {
api.idToken.setCustomClaim(`${namespace}/claims/email`, event.user.email);
api.accessToken.setCustomClaim(`${namespace}/email`, event.user.email);
}
};
And Rule:和规则:
function addEmailToAccessToken(user, context, callback) {
// This rule adds the authenticated user's email address to the access token.
const namespace = 'http://test.{our_local_development_route}:8888';
context.idToken[namespace + 'email'] = user.upn;
context.accessToken[namespace + 'email'] = user.email;
return callback(null, user, context);
}
I recently created a microservices architecture with Spring Cloud Gateway and Auth0.我最近使用 Spring Cloud Gateway 和 Auth0 创建了一个微服务架构。 I wrote about how I created it on the Auth0 blog .
我在Auth0 博客上写了我是如何创建它的。 That's not the interesting part.
那不是有趣的部分。 The interesting part is JHipster generates a
ReactiveJwtDecoder
that calls a /userinfo
endpoint if some claims aren't available in the access token.有趣的部分是 JHipster 生成一个
ReactiveJwtDecoder
,如果某些声明在访问令牌中不可用,它会调用/userinfo
端点。 This way, the access token is enriched with identity information before it's relayed to downstream microservices.这样,在将访问令牌中继到下游微服务之前,访问令牌会使用身份信息进行丰富。
@Bean
ReactiveJwtDecoder jwtDecoder(ReactiveClientRegistrationRepository registrations) {
Mono<ClientRegistration> clientRegistration = registrations.findByRegistrationId("oidc");
return clientRegistration
.map(oidc ->
createJwtDecoder(
oidc.getProviderDetails().getIssuerUri(),
oidc.getProviderDetails().getJwkSetUri(),
oidc.getProviderDetails().getUserInfoEndpoint().getUri()
)
)
.block();
}
private ReactiveJwtDecoder createJwtDecoder(String issuerUri, String jwkSetUri, String userInfoUri) {
NimbusReactiveJwtDecoder jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(jHipsterProperties.getSecurity().getOauth2().getAudience());
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return new ReactiveJwtDecoder() {
@Override
public Mono<Jwt> decode(String token) throws JwtException {
return jwtDecoder.decode(token).flatMap(jwt -> enrich(token, jwt));
}
private Mono<Jwt> enrich(String token, Jwt jwt) {
// Only look up user information if identity claims are missing
if (jwt.hasClaim("given_name") && jwt.hasClaim("family_name")) {
return Mono.just(jwt);
}
// Retrieve user info from OAuth provider if not already loaded
return users.get(
jwt.getSubject(),
s -> {
WebClient webClient = WebClient.create();
return webClient
.get()
.uri(userInfoUri)
.headers(headers -> headers.setBearerAuth(token))
.retrieve()
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
.map(userInfo ->
Jwt
.withTokenValue(jwt.getTokenValue())
.subject(jwt.getSubject())
.audience(jwt.getAudience())
.headers(headers -> headers.putAll(jwt.getHeaders()))
.claims(claims -> {
String username = userInfo.get("preferred_username").toString();
// special handling for Auth0
if (userInfo.get("sub").toString().contains("|") && username.contains("@")) {
userInfo.put("email", username);
}
// Allow full name in a name claim - happens with Auth0
if (userInfo.get("name") != null) {
String[] name = userInfo.get("name").toString().split("\\s+");
if (name.length > 0) {
userInfo.put("given_name", name[0]);
userInfo.put("family_name", String.join(" ", Arrays.copyOfRange(name, 1, name.length)));
}
}
claims.putAll(userInfo);
})
.claims(claims -> claims.putAll(jwt.getClaims()))
.build()
);
}
);
}
};
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.