为啥我收到 AuthenticationCredentialsNotFoundException?
Posted
技术标签:
【中文标题】为啥我收到 AuthenticationCredentialsNotFoundException?【英文标题】:Why I'm getting AuthenticationCredentialsNotFoundException?为什么我收到 AuthenticationCredentialsNotFoundException? 【发布时间】:2017-08-17 09:28:07 【问题描述】:我想为我的应用程序配置 OAuth2 身份验证。 我有下一个配置:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
@Override
protected MethodSecurityExpressionHandler createExpressionHandler()
return new OAuth2MethodSecurityExpressionHandler();
@Configuration
@EnableAuthorizationServer
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter
private static final String[] GRANT_TYPES = "password", "refresh_token";
private static final String[] SCOPES = "read", "write";
private final SecurityConfigurationProperties securityConfigurationProperties;
private final AuthenticationProvider authenticationProvider;
private final OAuth2AccessTokenRepository oAuth2AccessTokenRepository;
private final OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception
clients.inMemory()
.withClient(securityConfigurationProperties.getClientId())
.authorizedGrantTypes(GRANT_TYPES)
.authorities(UserRole.USER.getName())
.scopes(SCOPES)
.secret(securityConfigurationProperties.getClientSecret())
.accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime())
.refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime());
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager())
.approvalStoreDisabled();
@Bean
public AuthenticationManager authenticationManager()
return new ProviderManager(Collections.singletonList(authenticationProvider));
@Bean
public TokenStore tokenStore()
return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository);
@Bean
@Primary
public DefaultTokenServices tokenServices()
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAuthenticationManager(authenticationManager());
return tokenServices;
@Configuration
@EnableResourceServer
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter
private static final String RESOURCE_ID = "api";
private final TokenStore tokenStore;
@Override
public void configure(final ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
@Override
public void configure(final HttpSecurity http) throws Exception
http.anonymous().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SecurityConfig extends WebSecurityConfigurerAdapter
private final ApiUserDetailsService apiUserDetailsService;
private final AuthenticationProvider authenticationProvider;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(authenticationProvider);
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/").authenticated();
我也有我的自定义AuthenticationProvider
:
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserAuthenticationProvider implements AuthenticationProvider
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(final Authentication authentication)
throws AuthenticationException
final String email = authentication.getName();
final String password = authentication.getCredentials().toString();
return userRepository.findByEmail(email)
.filter(user -> passwordEncoder.matches(password, user.getPassword()))
.map(this::signInUser)
.orElseThrow(() -> new BadCredentialsException("Failed to authenticate"));
@Override
public boolean supports(final Class<?> authentication)
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
private Authentication signInUser(final User user)
final ApiUser springSecurityUser =
new ApiUser(user.getEmail(), user.getPassword(), user.getRoles());
final Authentication authentication = new UsernamePasswordAuthenticationToken(springSecurityUser,
user.getId(), springSecurityUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
return authentication;
一切都适用于令牌我从 /oauth/token 端点获取访问和刷新令牌,但是当我尝试使用 @PreAuthorize
注释访问资源时出现错误。
链接http://localhost:8080/users/me?access_token=8450e2f3-2ecb-4e88-b304-685b22c2ad65
我也尝试将"Authorization: Bearer 8450e2f3-2ecb-4e88-b304-685b22c2ad65"
添加到标题
"timestamp": 1490358162182,
"status": 403,
"error": "Forbidden",
"exception": "org.springframework.security.authentication.AuthenticationCredentialsNotFoundException",
"message": "Access Denied",
"path": "/users/me"
我的端点:
@PreAuthorize("hasRole('ROLE_USER')")
@RequestMapping(value = RestPath.Users.ME, method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity userInfo()
return ResponseEntity.noContent().build();
也许有人已经在相同的配置下遇到过这样的异常。
【问题讨论】:
【参考方案1】:好的,所以我的配置中的主要问题是在 SecurityConfiguration 类中。根据这篇文章https://***.com/a/42836521/2055854,我添加了注释@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
。
现在看起来:
@Configuration
@EnableWebSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private AuthenticationProvider authenticationProvider;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(authenticationProvider);
我也改变了一些配置:
@Configuration
public class OAuth2Config
@Configuration
@EnableResourceServer
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public static class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter
public static final String RESOURCE_ID = "api";
private static final String AUTHORIZATION = "Authorization";
private static final String BEARER = "Bearer";
private static final String ACCESS_TOKEN = "access_token";
private final TokenStore tokenStore;
@Override
public void configure(final ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
@Override
public void configure(final HttpSecurity http) throws Exception
http.csrf().disable()
.authorizeRequests().anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
@Configuration
@EnableAuthorizationServer
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public static class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter
private static final String[] GRANT_TYPES = "password", "refresh_token";
private static final String[] SCOPES = "read", "write";
private final SecurityConfigurationProperties securityConfigurationProperties;
private final AccessTokenRepository oAuth2AccessTokenRepository;
private final RefreshTokenRepository oAuth2RefreshTokenRepository;
private final AuthenticationProvider authenticationProvider;
private final UserDetailsService userDetailsService;
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception
clients.inMemory()
.withClient(securityConfigurationProperties.getClientId())
.authorizedGrantTypes(GRANT_TYPES)
.authorities(UserRole.USER.getName())
.secret(securityConfigurationProperties.getClientSecret())
.scopes(SCOPES)
.resourceIds(OAuth2ResourceServerConfig.RESOURCE_ID)
.accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime())
.refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime());
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager())
.userDetailsService(userDetailsService);
public AuthenticationManager authenticationManager()
return new ProviderManager(Collections.singletonList(authenticationProvider));
@Bean
public TokenStore tokenStore()
return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository);
@Bean
@Primary
public DefaultTokenServices tokenServices()
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAuthenticationManager(authenticationManager());
return tokenServices;
现在一切正常。
【讨论】:
以上是关于为啥我收到 AuthenticationCredentialsNotFoundException?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我收到 AuthenticationCredentialsNotFoundException?
为啥我收到 AbstractDynamicObject$CustomMessageMissingMethodException 错误?