我正在实施自定义' AuthenticationProvider'。如果没有经过身份验证,我会将异常置于“认证”状态。功能如下图所示。
public class DelegatingLdapAuthenticationProvider implements AuthenticationProvider {
private ActiveDirectoryLdapAuthenticationProvider primaryProvider;
private List<ActiveDirectoryLdapAuthenticationProvider> secondaryProviders = new ArrayList<>();
public DelegatingLdapAuthenticationProvider() {
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Authentication result = null;
AuthenticationException exception = null;
try {
result = primaryProvider.authenticate(authentication);
} catch (AuthenticationException e) {
exception = e;
for (ActiveDirectoryLdapAuthenticationProvider secondaryProvider : secondaryProviders) {
try {
result = secondaryProvider.authenticate(authentication);
if (result.isAuthenticated()) {
break;
}
} catch (AuthenticationException e1) {
exception = e;
}
}
}
if (result == null || !result.isAuthenticated()) {
throw exception;
}
return result;
}
我有全局异常处理程序,如下所示。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({NoPermissionException.class})
@ResponseBody
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public Map<String, String> noPermission(NoPermissionException e) {
return createErrorResponse(e, "Don't have permissions");
}
@ExceptionHandler({Exception.class})
@ResponseBody
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, String> exceptionInProcessing(Exception e) {
return createErrorResponse(e, "Unable to process. Unknown error occurred: " + e.getMessage());
}
private Map<String, String> createErrorResponse(Exception e, String errorMessage) {
Map<String, String> errorResponse = new HashMap<>();
errorResponse.put("message", errorMessage);
errorResponse.put("reason", e.toString());
return errorResponse;
}
}
如果在“身份验证”中引发异常。函数,未调用全局异常处理程序。对于所有其他异常,它被调用。我想捕获全局异常处理程序中的异常并返回自定义错误消息。我怎样才能做到这一点?任何帮助赞赏。提前谢谢。
答案 0 :(得分:1)
GlobalExceptionHandler
用于控制器异常处理程序,但AuthenticationProvider
仍然在过滤器中,如果要处理AuthenticationException
,则需要处理它以实现AuthenticationEntryPoint
并覆盖commence
方法。
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException
AuthenticationException
和AccessDeniedException
已由ExceptionTranslationFilter
处理。您只需要注入AuthenticationEntryPoint
和AccessDeniedHandler
(处理AccessDeniedException
)
或者您可以在过滤器中捕获这些异常,然后在文件管理器中处理它,例如AuthenticationFailureHandler
中的AbstractAuthenticationProcessingFilter
答案 1 :(得分:0)
在控制器异常处理程序有机会捕获异常之前调用身份验证提供程序。
您可以覆盖AuthenticationFailureHandler来处理安全过滤器链级别的异常,请查看examples
documentation中描述的行为:
过滤器调用配置的AuthenticationManager来处理每个身份验证请求。身份验证成功或身份验证失败后的目标分别由AuthenticationSuccessHandler和AuthenticationFailureHandler策略接口控制。过滤器具有允许您设置这些属性的属性,以便您可以完全自定义行为
答案 2 :(得分:0)
正如@chaoluo已经说过你需要实现AuthenticationEntryPoint
并覆盖commence
方法。如果要返回错误JSON对象,可以执行以下操作:
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//create errorObj
PrintWriter writer = response.getWriter();
mapper.writeValue(writer, errorObj);
writer.flush();
}
答案 3 :(得分:0)
补充 @chaoluo 答案:
AuthenticationEntryPoint
接口并通过HandlerExceptionResolver
解决异常:@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint, AccessDeniedHandler {
@Autowired
private HandlerExceptionResolver resolver;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
resolver.resolveException(request, response, null, exception);
}
}
RestAuthenticationEntryPoint
注入您的 WebSecurityConfigurerAdapter
实现并将其用作 authenticationEntryPoint:@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint authenticationEntryPoint;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
HandlerExceptionResolver
解决了异常,我们可以使用典型的 Spring Web 错误处理,使用 @ControllerAdvice
和 @ExceptionHandler
注释:@RestControllerAdvice
public abstract class ErrorsControllerAdvice {
@ExceptionHandler
public ResponseEntity<?> handleException(Throwable exception, WebRequest webRequest, Locale locale) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED);
}
}