简体   繁体   中英

Spring Security: how to change HTTP Status for response?

On unsuccessful authorization I need to return HTTP 401 status. I use Spring Security and the following setup authorization:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatcher(ADMIN_MATCHERS)
                    .authorizeRequests()
                    .antMatchers(ADMIN_MATCHERS)
                    .access("hasRole('ADMIN')")
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .usernameParameter(USERNAME)
                    .passwordParameter(PASSWORD)
                    .loginPage(ADMIN_LOGIN)
                    .permitAll()
                    .loginProcessingUrl("/admin/login/auth")
                    .failureHandler(customAuthFailureHandler)
                    .successHandler(successHandler())
                    .and()
                    .logout()
                    .logoutUrl("/admin/logout")
                    .logoutSuccessUrl(ADMIN_LOGIN)
                    .and()
                    .exceptionHandling()
                    .accessDeniedPage(ADMIN_LOGIN)
                    .and()
                    .csrf().disable()
                    .httpBasic();

I use failureHandler() to handle it.

I wrote a custom handler:

@Component("customAuthFailureHandler")
public class CustomAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    private static final String ADMIN_LOGIN = "/admin/login";
    private static final Integer STATUS_UNAUTHORIZED = 401;
    private static final String RESPONSE_CODE_KEY = "Response-Code";
    private static final String RESPONSE_BAD_CREDENTIALS = "bad-credentials";

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setStatus(STATUS_UNAUTHORIZED);
        response.addHeader(RESPONSE_CODE_KEY, RESPONSE_BAD_CREDENTIALS);
        getRedirectStrategy().sendRedirect(request, response, ADMIN_LOGIN);
    }
}

Header returns OK, but with status 302 instead of 401.

当您调用 sendError 时,它会将请求分派到 /error (它是 Spring Boot 注册的错误处理代码。但是,Spring Security 会拦截 /error 并看到您未通过身份验证,从而将您重定向到登录表单。

Handler :

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
                                                                  final HttpHeaders headers,
                                                                  final HttpStatus status,
                                                                  final WebRequest request) {
        String error = "Malformed JSON request";
        return buildResponseEntity(new ApiError(HttpStatus.BAD_REQUEST, error, ex));
    }

    private ResponseEntity<Object> buildResponseEntity(ApiError apiError) {
        return new ResponseEntity<>(apiError, apiError.getStatus());
    }


    /**
     * Handle NoSuchElementException
     **/
    @ExceptionHandler(NoSuchElementException.class)
    protected ResponseEntity<Object> handleEntityNotFound(NoSuchElementException ex) {
        ApiError apiError = new ApiError(HttpStatus.NOT_FOUND);
        apiError.setMessage(apiError.getMessage());
        return buildResponseEntity(apiError);
    }

    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
        ApiError apiError = new ApiError(HttpStatus.NOT_FOUND);
        //apiError.setMessage(Translator.toLocale(apiError.getMessage(), null));
        apiError.setMessage(ex.getMessage());
        return buildResponseEntity(apiError);
    }
}

ApiError:

public class ApiError {

    @Getter
    @Setter
    private HttpStatus status;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime timestamp;

    @Setter
    @Getter
    private String message;

    @Setter
    @Getter
    private String debugMessage;

    @Setter
    @Getter
    private List<ApiValidationError> subErrors;

    private ApiError() {
        timestamp = LocalDateTime.now();
    }

    public ApiError(HttpStatus status) {
        this();
        this.status = status;
    }

    ApiError(HttpStatus status, Throwable ex) {
        this();
        this.status = status;
        this.message = "Unexpected error";
        this.debugMessage = ex.getLocalizedMessage();
    }

    public ApiError(HttpStatus status, String message, Throwable ex) {
        this();
        this.status = status;
        this.message = message;
        this.debugMessage = ex.getLocalizedMessage();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM