我想为我的应用程序配置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();
}
也许有人已经有相同配置的例外。
答案 0 :(得分:1)
好的,我配置中的主要问题是在SecurityConfiguration类中。我已根据此帖See here添加了注释@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;
}
}
}
我也改变了一些配置:
@strTablename
现在一切都按预期工作了。