簡體   English   中英

捕獲 AuthenticationProvider 中拋出的異常

[英]Catching exception thrown in AuthenticationProvider

我正在實現自定義的“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;
    }
}

當在 'authenticate' 函數內拋出異常時,不會調用全局異常處理程序。 對於所有其他異常,它正在被調用。 我想在全局異常處理程序中捕獲異常並返回自定義錯誤消息。 我怎樣才能做到這一點? 任何幫助表示贊賞。 提前致謝。

GlobalExceptionHandler用於控制器異常處理程序,但AuthenticationProvider仍在過濾器中,如果要處理AuthenticationException ,則需要對其進行處理以實現AuthenticationEntryPoint並覆蓋commence方法。

public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException

AuthenticationExceptionAccessDeniedException已經由ExceptionTranslationFilter處理。 你只需要注入AuthenticationEntryPointAccessDeniedHandler (它們處理AccessDeniedException

或者您可以在過濾器中捕獲這些異常,然后在過濾器中處理它,例如AbstractAuthenticationProcessingFilter AuthenticationFailureHandler

在控制器異常處理程序有機會捕獲異常之前調用身份驗證提供程序。

您可以覆蓋AuthenticationFailureHandler來處理安全過濾器鏈級別的異常,查看示例

文檔中描述的行為:

過濾器調用配置的 AuthenticationManager 來處理每個身份驗證請求。 身份驗證成功或身份驗證失敗后的目的地分別由 AuthenticationSuccessHandler 和 AuthenticationFailureHandler 策略接口控制。 過濾器具有允許您設置這些屬性的屬性,以便您可以完全自定義行為

正如@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();
}

補充@chaoluo的回答:

  1. 實現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);
    }

}
  1. 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);
    }
}
  1. 現在因為我們通過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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM