我注意到我的
ResponseEntityExceptionHandler
无法处理Spring启动应用程序中Spring Security引发的异常。
InvalidGrantException
用例很简单:如果用户当前被禁用,我想向我的客户机s.t抛出一个适当的错误。它可以相应地显示一条消息。
{
error: "invalid_grant",
error_description: "User is disabled"
}
我看到
this question
但出于某种原因,我的
AuthFailureHandler
未被调用:
@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
@Component
public class AuthFailureHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
System.out.println("Hello World!");
}
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(customAuthEntryPoint());;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.authenticationEntryPoint(customAuthEntryPoint());
}
@Bean
public AuthenticationEntryPoint customAuthEntryPoint(){
return new AuthFailureHandler();
}
}
知道我错过了什么吗?
配置代码
这是我的
OAuth2Configuration
其中还包含
ResourceServerConfiguraerAdapter
@Configuration
@EnableAuthorizationServer
@EnableResourceServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
private final TokenStore tokenStore;
private final JwtAccessTokenConverter accessTokenConverter;
private final AuthenticationManager authenticationManager;
@Autowired
public OAuth2Configuration(TokenStore tokenStore, JwtAccessTokenConverter accessTokenConverter, AuthenticationManager authenticationManager) {
this.tokenStore = tokenStore;
this.accessTokenConverter = accessTokenConverter;
this.authenticationManager = authenticationManager;
}
@Value("${security.jwt.client-id}")
private String clientId;
@Value("${security.jwt.client-secret}")
private String clientSecret;
@Value("${security.jwt.scope-read}")
private String scopeRead;
@Value("${security.jwt.scope-write}")
private String scopeWrite;
@Value("${security.jwt.resource-ids}")
private String resourceIds;
private final static String WEBHOOK_ENDPOINTS = "/r/api/*/webhooks/**";
private final static String PUBLIC_ENDPOINTS = "/r/api/*/public/**";
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(clientId)
.secret(clientSecret)
.scopes(scopeRead, scopeWrite)
.resourceIds(resourceIds)
.accessTokenValiditySeconds(60*60*24*7 * 2)
.refreshTokenValiditySeconds(60*60*24*7 * 12)
.authorizedGrantTypes("password", "refresh_token");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
enhancerChain.setTokenEnhancers(Collections.singletonList(accessTokenConverter));
endpoints.tokenStore(tokenStore)
.pathMapping("/oauth/authorize", "/api/v1/oauth/authorize")
.pathMapping("/oauth/check_token", "/api/v1/oauth/check_token")
.pathMapping("/oauth/confirm_access", "/api/v1/oauth/confirm_access")
.pathMapping("/oauth/error", "/api/v1/oauth/error")
.pathMapping("/oauth/token", "/api/v1/oauth/token")
.accessTokenConverter(accessTokenConverter)
.tokenEnhancer(enhancerChain)
.reuseRefreshTokens(false)
.authenticationManager(authenticationManager);
}
@Controller
public class ForwardController {
@RequestMapping(value = "/sitemap.xml", method = RequestMethod.GET)
public String redirectSitemapXml(HttpServletRequest request) {
return "forward:/a/web/assets/sitemap.xml";
}
@RequestMapping(value = "/robots.txt", method = RequestMethod.GET)
public String redirectRobotTxt(HttpServletRequest request) {
return "forward:/a/web/assets/robots.txt";
}
@RequestMapping(value = "/*", method = RequestMethod.GET)
public String redirectRoot(HttpServletRequest request) {
return "forward:/a/web/index.html";
}
@RequestMapping(value = "/a/**/{path:[^.]*}", method = RequestMethod.GET)
public String redirectClients(HttpServletRequest request) {
String requestURI = request.getRequestURI();
if (requestURI.startsWith("/a/admin/")) {
return "forward:/a/admin/index.html";
}
if (requestURI.startsWith("/a/swagger/")) {
return "forward:/a/swagger/swagger-ui.html#/";
}
return "forward:/a/web/index.html";
}
}
@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.antMatchers("/**")
.requiresSecure()
.and()
.exceptionHandling()
.and()
.authorizeRequests()
.antMatchers(PUBLIC_ENDPOINTS, WEBHOOK_ENDPOINTS)
.permitAll()
.antMatchers(HttpMethod.GET, "/*")
.permitAll()
.antMatchers("/r/api/**")
.authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.resourceId(resourceIds)
.authenticationEntryPoint(customAuthEntryPoint());
}
@Component
public class AuthFailureHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
System.out.println("Hello");
throw authException;
}
}
@Bean
public AuthenticationEntryPoint customAuthEntryPoint(){
return new AuthFailureHandler();
}
}
}
另外,这里是
WebSecurityConfigurerAdapter
虽然我不认为这在这里起作用:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
private final UserDetailsService userDetailsService;
private final DataSource dataSource;
@Autowired
public WebSecurityConfig(@Qualifier("appUserDetailsService") UserDetailsService userDetailsService, DataSource dataSource) {
this.userDetailsService = userDetailsService;
this.dataSource = dataSource;
}
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
public void configure(WebSecurity web) throws Exception {
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder())
.and()
.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userDetailsService);
return daoAuthenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel()
.requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
.requiresSecure();
}
}