【发布时间】:2019-11-19 10:05:56
【问题描述】:
我正在尝试使用 Spring Boot 和依赖项创建 Oauth 身份验证/授权服务器 * spring-security-oauth2-autoconfigure * nimbus-jose-jwt
问题是我不想指定 UserDetailsService,因为有关用户帐户的信息位于另一个不公开密码的服务中。该服务只有一个 API,其中输入是用户/密码,输出是用户信息(如果用户存在/凭据正确)。
所以我的代码/配置有点偏离文档。
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//injections
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(jwtTokenStore)
.accessTokenConverter(accessTokenConverter)
.authenticationManager(authenticationManager);
}
}
和
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//injections
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(travelerAuthenticationProvider); //my custom // authentication provider that calls the other service for checking credentials
}
}
和
@Component
public class TravelerAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(TravelerAuthenticationProvider.class);
private OrderTravelerProfileClient travelerProfileClient;
public TravelerAuthenticationProvider(OrderTravelerProfileClient travelerProfileClient) {
this.travelerProfileClient = travelerProfileClient;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.getName() == null || (authentication.getCredentials().toString().isEmpty())) {
return null;
}
var username = authentication.getName();
var password = authentication.getCredentials().toString();
try {
travelerProfileClient.authenticate(username, password);
} catch (Exception e) {
LOGGER.error("checking traveler {} credentials failed", username, e);
throw new BadCredentialsException("wrong traveler credentials");
}
var authorities = Set.of(new SimpleGrantedAuthority("traveler"));
var updatedAuthentication = new UsernamePasswordAuthenticationToken(username, password, authorities);
return updatedAuthentication;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
与 client_credentials 和密码流相关的所有内容都有效,但是当我尝试使用 refresh_token 流时,它抱怨 UserDetailsService is required。我应该如何在不定义 UserDetailsService 并仅中继我的自定义身份验证提供程序的情况下解决问题?
更新: 显然 refresh_token 流程对身份验证(凭据)进行了重新检查,这需要另一个身份验证提供程序用于 PreAuthenticatedAuthenticationToken.class 类型。
所以我像这样创建了一个新的身份验证提供程序:
@Component
public class TravelerRefreshTokenBasedAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(TravelerRefreshTokenBasedAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
var currentAuthentication = (PreAuthenticatedAuthenticationToken) authentication;
//.....
return updatedAuthentication;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(PreAuthenticatedAuthenticationToken.class);
}
}
并将我的安全配置更新为:
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//injections
//this bean will be more configured by the method below and it will be used by spring boot
//for authenticating requests. Its kind of an equivalent to userDetailsService
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(travelerUserPassBasedAuthenticationProvider);
authenticationManagerBuilder.authenticationProvider(travelerRefreshTokenBasedAuthenticationProvider);
}
}
问题是 spring 在 refresh_token 流程中无法识别我的身份验证提供程序,并尝试使用默认提供程序。而默认的是尝试使用一个不存在的 UserDetailsService。
我也觉得我不需要创建另一个提供程序,我可以重用以前的提供程序。因为 spring 未能使用我的自定义提供程序的检查是对用户/通过的检查;我在以前的身份验证提供程序中所做的。
总而言之,到现在为止,我觉得我必须介绍我的自定义提供程序,以使 refresh_token 流与密码流相比具有不同的弹出方式
【问题讨论】:
标签: spring spring-boot oauth-2.0 spring-security-oauth2 refresh-token