使用 spring security 的 oauth2 刷新令牌调用失败,错误:需要 UserDetailsService
Posted
技术标签:
【中文标题】使用 spring security 的 oauth2 刷新令牌调用失败,错误:需要 UserDetailsService【英文标题】:Refresh token call fails using spring security an oauth2 with error: UserDetailsService is required 【发布时间】:2017-10-06 03:52:49 【问题描述】:我正在使用 Spring Security OAuth2 进行授权。尝试刷新令牌时出现错误:UserDetailsService is required
(有趣的是,我仅在 unix 机器上而不是在 Windows 上收到此错误)。我正在使用 Spring OAuth2 2.0.7 版。
由于某种原因,DefaultTokenService
中的AuthenticationManager
不为空,它会尝试对用户进行身份验证以检查他是否仍然存在。我认为它被初始化是因为一些 spring security 与 spring oauth2 配置问题。
我没有使用任何自定义UserDetailsService
,因此此时它不应该对用户进行身份验证。但是,当我调试它时,我看到它尝试使用 WebSecurityConfigurerAdapter
中的一个并出现此错误。即使我提供了我的自定义虚拟对象UserDetailsService
,它也没有使用那个,而是尝试使用另一个为空的虚拟对象。我在这里想念什么吗?我不知道为什么会这样?
这是我的 Oauth2 配置
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter
@Autowired
private MySpringTokenStore tokenStore;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private MyClientDetailsServiceImpl clientDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients.withClientDetails(clientDetailsService);
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception
security.allowFormAuthenticationForClients();
@Bean
public TokenStore tokenStore()
return new InMemoryTokenStore();
这是我的 Spring 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.authorizeRequests()
.antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll()
.antMatchers("/login.jsp", "/login").permitAll()
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
.sessionManagement().sessionFixation().none();
// @formatter:on
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().antMatchers("/index*", "/myRest/events/**", "/events/**", "/myRest/events", "/events", "/swagger/**", "/kibana/**",
"/elastic/**", "/version/**", "/api-docs/**", "/js/**", "/oauth/uncache_approvals", "/oauth/cache_approvals");
【问题讨论】:
见github.com/spring-projects/spring-security-oauth/issues/813 另见github.com/spring-projects/spring-security-oauth/issues/685 【参考方案1】:授权服务器端点需要UserDetailsService
。在您的 OAuth2Config
类中配置用户详细信息服务,如下所示:
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore);
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
也可以在WebSecurityConfigurerAdapter
中配置:
@Autowired
private AuthorizationServerEndpointsConfiguration endpoints;
@Override
protected void configure(HttpSecurity http) throws Exception
if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride())
UserDetailsService userDetailsService = http.getSharedObject(UserDetailsService.class);
endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
// @formatter:off
http
.authorizeRequests()
.antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll()
.antMatchers("/login.jsp", "/login").permitAll()
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
.sessionManagement().sessionFixation().none();
// @formatter:on
【讨论】:
不,这不是真的。 Oauth2 配置不需要该服务,也可以留空。我也尝试过提供该服务的实现,它也抛出了同样的异常。我已经解决了这个问题。问题是配置的顺序(因为它们包含一些对象)。我已将 OAuth2 配置的顺序设置为(例如)100,将 Web Security 配置的顺序设置为 101。这样就可以了。【参考方案2】:如果实现自定义DefaultTokenServices
,我们不需要UserDetailsService
。
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints
// ...
.tokenServices(tokenServices(endpoints));
public AuthorizationServerTokenServices tokenServices(final AuthorizationServerEndpointsConfigurer endpoints)
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
// ...
tokenServices.setAuthenticationManager(
new ProviderManager(List.of(new MyCustomAuthProvider())));
return tokenServices;
The commit message 说:
将 AuthenticationManager 添加到默认令牌服务
这样它就可以用于在刷新时检查用户帐户的更改 令牌授予。如果全局 UserDetailsService 可用,它将是 用作默认值(例如,如果用户有 GlobalAuthenticationConfigurer)。 它通过构造 PreAuthenticationAuthenticationProvider 来工作 并使用它在 DefaultTokenServices 中对用户进行身份验证。 要自定义该过程,用户可以创建自己的 DefaultTokenServices 并注入一个 AuthenticationManager。
修复gh-401
【讨论】:
【参考方案3】:补充@VijayaNandwana 的回答并考虑@FilipMajernik 的评论,
我为OAuthConfig
创建了一个类,并且使顺序小于扩展WebSecurityConfigurerAdapter
的类。
@Configuration
@Order(1)
public class OAuthConfig extends AuthorizationServerConfigurerAdapter
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JdbcTemplate jdbcTemplate;
@Bean
public TokenStore tokenStore()
return new JdbcTokenStore(jdbcTemplate.getDataSource());
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore());
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
以及扩展WebSecurityConfigurerAdapter
的类
@Configuration
@EnableWebSecurity
@Order(2)
public class SecurityConfig extends WebSecurityConfigurerAdapter
//Configurations
【讨论】:
【参考方案4】:授权端点需要一个 UserDetailsService。
添加这个:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore());
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
【讨论】:
以上是关于使用 spring security 的 oauth2 刷新令牌调用失败,错误:需要 UserDetailsService的主要内容,如果未能解决你的问题,请参考以下文章
在没有 servlet api 的 webflux 项目中使用 OAuth2 和 Spring Security OAuth2 和 reactor netty
具有密码授予类型的 WebClient 的 Spring Security OAuth 客户端不要求新令牌
获取'无法在grails Spring安全性休息中调用null对象上的方法loadUserByUsername()'
Oaut2RestTemplate 与 client_credentials 错误(不允许匿名)
Spring Framework,Spring Security - 可以在没有 Spring Framework 的情况下使用 Spring Security?