[英]No AuthenticationProvider found on refresh token - Spring OAuth2 java config
I have a Spring Boot project in which I've configured a Spring OAuth2 authentication process which partially works. 我有一个Spring Boot项目,在其中配置了部分起作用的Spring OAuth2身份验证过程。 I can authenticate OK but when I'm trying to get a refresh token I get an exception.
我可以验证OK,但是当我尝试获取刷新令牌时会出现异常。
OAuth configuration: OAuth配置:
@Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "xxx";
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Value("${clientDetailsService.clientName}")
private String clientName;
@Value("${clientDetailsService.clientSecret}")
private String clientSecret;
@Autowired
@Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("tokenServices")
private AuthorizationServerTokenServices tokenServices;
@Autowired
@Qualifier("codeServices")
private AuthorizationCodeServices codeServices;
@Autowired
@Qualifier("requestFactory")
private OAuth2RequestFactory requestFactory;
@Autowired
@Qualifier("tokenGranter")
private TokenGranter tokenGranter;
private final TokenStore tokenStore = new InMemoryTokenStore();
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.setClientDetailsService(clientDetailsService);
endpoints.tokenServices(tokenServices)
.tokenStore(tokenStore)
.authorizationCodeServices(codeServices)
.authenticationManager(authenticationManager)
.requestFactory(requestFactory)
.tokenGranter(tokenGranter);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Bean(name = "tokenGranter")
@Primary
public TokenGranter tokenGranter() {
final List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, codeServices, clientDetailsService, requestFactory));
tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetailsService, requestFactory));
tokenGranters.add(new ImplicitTokenGranter(tokenServices, clientDetailsService, requestFactory));
tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, requestFactory));
tokenGranters.add(new CustomTokenGranter(authenticationManager, tokenServices, clientDetailsService, requestFactory));
return new CompositeTokenGranter(tokenGranters);
}
@Bean
@Primary
public ClientDetailsService clientDetailsService(){
final InMemoryClientDetailsServiceBuilder builder = new InMemoryClientDetailsServiceBuilder();
builder.withClient(clientName)
.authorizedGrantTypes("password", "refresh_token")
.authorities("USER")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret(clientSecret);
try {
return builder.build();
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
@Bean(name = "tokenServices")
@Primary
public AuthorizationServerTokenServices tokenServices() {
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setTokenStore(tokenStore);
tokenServices.setAuthenticationManager(authenticationManager);
return tokenServices;
}
@Bean(name = "requestFactory")
@Primary
public OAuth2RequestFactory requestFactory() {
return new DefaultOAuth2RequestFactory(clientDetailsService);
}
@Bean(name = "codeServices")
@Primary
public AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
}
I also have some custom components defined, like a custom Token Granter, custom authentication provider etc. I'll post them if necessary. 我还定义了一些自定义组件,例如自定义令牌授予者,自定义身份验证提供程序等。如有必要,我将发布它们。
As I said, authentication flow works OK. 正如我所说,身份验证流程可以正常运行。 When I POST to /oauth/token I get a token and a refresh token, but when I then try to exchange my refresh token for a new token (by POSTing http://localhost:8080/oauth/token with grant_type=refresh_token and refresh_token=my refresh token) I get an exception:
当我发布到/ oauth / token时,我得到一个令牌和一个刷新令牌,但是当我尝试将我的刷新令牌交换为一个新令牌时(通过使用grant_type = refresh_token POST http:// localhost:8080 / oauth / token , refresh_token =我的刷新令牌)出现异常:
No AuthenticationProvider found for org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken 找不到org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken的AuthenticationProvider
Where do I set the authentication provider? 在哪里设置身份验证提供程序? How do I get Spring to use my custom authentication provider for refresh tokens also?
如何使Spring还将我的自定义身份验证提供程序也用于刷新令牌?
I fixed this by explicitly defining a PreAuthenticationProvider: 我通过显式定义PreAuthenticationProvider来解决此问题:
@Component("preAuthProvider")
public class CustomPreAuthProvider extends PreAuthenticatedAuthenticationProvider {
@Autowired
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> userService;
public CustomPreAuthProvider(){
super();
}
@PostConstruct
public void init(){
super.setPreAuthenticatedUserDetailsService(userService);
}
}
and then a custom userservice: 然后是自定义用户服务:
@Service
public class CustomPreAuthUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
@Override
public final UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token) {
...
}
}
and adding this provider to the oauth2 config: 并将此提供程序添加到oauth2配置中:
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
@Qualifier("preAuthProvider")
private AuthenticationProvider preAuthProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider).authenticationProvider(preAuthProvider);
}
I can not be disagree with Jesper's answer, but in my case, that same error has been fixed removing: 我不能不同意Jesper的回答,但就我而言,该错误已得到修复,已删除:
tokenServices.setAuthenticationManager(authenticationManager)
from tokenService()
来自
tokenService()
As an alternative way to Jesper's answer, if you want to reuse your current UserDetailsService
for this purpose, you can just do it the same way as Spring does it with their DefaultTokenServices
: 作为Jesper回答的一种替代方法,如果您想为此目的重用当前的
UserDetailsService
,则可以使用与Spring对其DefaultTokenServices
相同的方式进行操作:
@Bean
public CustomTokenServices tokenServices() {
CustomTokenServices tokenServices = new CustomTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(false);
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setAuthenticationManager(createPreAuthProvider());
return tokenServices;
}
private ProviderManager createPreAuthProvider() {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
return new ProviderManager(Arrays.asList(provider));
}
UserDetailsService
is autowired into this @Configuration
class. UserDetailsService
自动连接到此@Configuration
类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.