如何从Spring Security获得访问令牌



我使用spring云网关创建微服务网关。网关配置了OAuth2协议。应用程序已成功通过身份验证。如何从认证用户的网关获取访问令牌?

我实现了GlobalFilter来获取Principal。实现如下:

return exchange.getPrincipal()
.defaultIfEmpty(DEFAULT_PRINCIPAL).map(principal -> {
// adds header to proxied request
ServerHttpRequest.Builder b = exchange.getRequest().mutate();
OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) principal;
OAuth2User p = (OAuth2User) auth.getPrincipal();
String userId = (String) p.getAttributes()
.getOrDefault("sub", new String());
String firstName = (String) p.getAttributes()
.getOrDefault("given_name", new String());
String lastName = (String) p.getAttributes()
.getOrDefault("family_name", new String());
String name = (String) p.getAttributes()
.getOrDefault("preferred_username",
new String());
String email = (String) p.getAttributes()
.getOrDefault("email",
new String());
b.build();
return exchange;
}).flatMap(chain::filter);

private static Principal DEFAULT_PRINCIPAL = () -> "<EMPTY>";

下面是SecurityConfig

public SecurityWebFilterChain configure(ServerHttpSecurity http) {
var authenticateExchangeOrUrl = http.authorizeExchange().pathMatchers(s.trim()).authenticated().and();
securityFilterChain = authenticateExchangeOrUrl.oauth2Client().and().oauth2Login().and();
return securityFilterChain
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.build();
}

SecurityConfig中有@EnableWebFluxSecurity注释。在应用程序中。添加yamlspring.main.web-application-type: reactive

如何获取认证用户的access Token ?

您可以创建一个自定义配置类,并使用@Configuration注释它。

步骤1:获取ServerOAuth2AuthorizedClientRepository Interface的实例

@Autowired
private ServerOAuth2AuthorizedClientRepository clientRegistrationRepository;

步骤2:应用全局过滤器并从OAuth2AuthorizedClient获取令牌

// For Getting token from request
SecurityContextImpl context =
exchange.getSession().toProcessor().block().getAttribute("SPRING_SECURITY_CONTEXT");
OAuth2AuthenticationToken oauthToken =
(OAuth2AuthenticationToken) context.getAuthentication();
Mono<OAuth2AuthorizedClient> authorizedClient = clientRegistrationRepository
.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(),
context.getAuthentication(), exchange);
OAuth2AuthorizedClient client = authorizedClient.toProcessor().block();
String accessToken = client.getAccessToken().getTokenValue();
LOG.info("Access Token value: {}", accessToken);

这是一个完整的配置类,它完美地完成了这项工作。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import reactor.core.publisher.Mono;
@Configuration
public class GatewayConfig {
private static final Logger LOG = LoggerFactory.getLogger(GatewayConfig.class);
@Autowired
private ServerOAuth2AuthorizedClientRepository clientRegistrationRepository;
@SuppressWarnings("deprecation")
@Bean
public GlobalFilter customGlobalFilter() {
return (exchange, chain) -> exchange.getPrincipal().map(principal -> {
if (principal instanceof OAuth2AuthenticationToken) {
// For Getting token from request
SecurityContextImpl context =
exchange.getSession().toProcessor().block().getAttribute("SPRING_SECURITY_CONTEXT");
OAuth2AuthenticationToken oauthToken =
(OAuth2AuthenticationToken) context.getAuthentication();
Mono<OAuth2AuthorizedClient> authorizedClient = clientRegistrationRepository
.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(),
context.getAuthentication(), exchange);
OAuth2AuthorizedClient client = authorizedClient.toProcessor().block();
String accessToken = client.getAccessToken().getTokenValue();
LOG.info("Access Token value: {}", accessToken);
}
return exchange;
}).flatMap(chain::filter).then(Mono.fromRunnable(() -> {
}));
}
}

相关内容

最新更新