【问题标题】: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();
}

也许有人已经在相同的配置下遇到过这样的异常。

【问题讨论】:

    标签: spring spring-security spring-security-oauth2


    【解决方案1】:

    好的,所以我的配置中的主要问题是在 SecurityConfiguration 类中。根据这篇文章https://stackoverflow.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;
            }
        }
    }
    

    现在一切正常。

    【讨论】:

      猜你喜欢
      • 2020-09-18
      • 2012-05-27
      • 2020-03-09
      • 2020-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多