Xử lý các ngoại lệ xác thực bảo mật mùa xuân với @ExceptionHandler


97

Tôi đang sử dụng Spring MVC @ControllerAdvice@ExceptionHandlerđể xử lý tất cả các ngoại lệ của REST Api. Nó hoạt động tốt đối với các ngoại lệ do bộ điều khiển mvc web ném ra nhưng nó không hoạt động đối với các ngoại lệ do các bộ lọc tùy chỉnh bảo mật mùa xuân đưa ra vì chúng chạy trước khi các phương thức bộ điều khiển được gọi.

Tôi có một bộ lọc bảo mật mùa xuân tùy chỉnh thực hiện xác thực dựa trên mã thông báo:

public class AegisAuthenticationFilter extends GenericFilterBean {

...

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        try {

            ...         
        } catch(AuthenticationException authenticationException) {

            SecurityContextHolder.clearContext();
            authenticationEntryPoint.commence(request, response, authenticationException);

        }

    }

}

Với điểm nhập tùy chỉnh này:

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
    }

}

Và với lớp này để xử lý các ngoại lệ trên toàn cầu:

@ControllerAdvice
public class RestEntityResponseExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler({ InvalidTokenException.class, AuthenticationException.class })
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public RestError handleAuthenticationException(Exception ex) {

        int errorCode = AegisErrorCode.GenericAuthenticationError;
        if(ex instanceof AegisException) {
            errorCode = ((AegisException)ex).getCode();
        }

        RestError re = new RestError(
            HttpStatus.UNAUTHORIZED,
            errorCode, 
            "...",
            ex.getMessage());

        return re;
    }
}

Những gì tôi cần làm là trả về một nội dung JSON chi tiết ngay cả cho AuthenticationException bảo mật mùa xuân. Có cách nào giúp bảo mật mùa xuân AuthenticationEntryPoint và spring mvc @ExceptionHandler hoạt động cùng nhau không?

Tôi đang sử dụng spring security 3.1.4 và spring mvc 3.2.4.


9
Bạn không thể ... Di (@)ExceptionHandlerchúc chỉ hoạt động nếu yêu cầu được xử lý bởi DispatcherServlet. Tuy nhiên ngoại lệ này xảy ra trước đó vì nó được ném bởi a Filter. Vì vậy, bạn sẽ không bao giờ có thể xử lý ngoại lệ này với một (@)ExceptionHandler.
M. Deinum

Được rồi! Bạn đúng. Có cách nào để trả về một nội dung json cùng với response.sendError của EntryPoint không?
Nicola

Có vẻ như bạn cần chèn một bộ lọc tùy chỉnh trước đó trong chuỗi để bắt Ngoại lệ và trả về tương ứng. Tài liệu liệt kê các bộ lọc, bí danh của chúng và thứ tự chúng được áp dụng: docs.spring.io/spring-security/site/docs/3.1.4.RELEASE/…
Romski

1
Nếu vị trí duy nhất bạn cần JSON thì chỉ cần tạo / ghi nó vào bên trong EntryPoint. Bạn có thể muốn xây dựng đối tượng ở đó và chèn một đối tượng MappingJackson2HttpMessageConvertervào đó.
M. Deinum

@ M.Deinum Tôi sẽ cố gắng xây dựng json bên trong điểm vào.
Nicola

Câu trả lời:


58

Được rồi, tôi đã thử tự viết json như được đề xuất từ ​​AuthenticationEntryPoint và nó hoạt động.

Chỉ để thử nghiệm, tôi đã thay đổi AutenticationEntryPoint bằng cách loại bỏ response.sendError

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

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

        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");

    }
}

Bằng cách này, bạn có thể gửi dữ liệu json tùy chỉnh cùng với 401 trái phép ngay cả khi bạn đang sử dụng Spring Security AuthenticationEntryPoint.

Rõ ràng là bạn sẽ không xây dựng json như tôi đã làm cho mục đích thử nghiệm nhưng bạn sẽ tuần tự hóa một số cá thể lớp.


3
Ví dụ sử dụng Jackson: ObjectMapper mapper = new ObjectMapper (); mapper.writeValue (response.getOutputStream (), FailResponse mới (401, authException.getLocalizedMessage (), "Truy cập bị từ chối", ""));
Cyrusmith

1
Tôi biết câu hỏi hơi cũ, nhưng bạn đã đăng ký AuthenticationEntryPoint của mình với SecurityConfig chưa?
leventunver 21/12/16

1
@leventunver Tại đây bạn có thể tìm thấy cách đăng ký điểm vào: stackoverflow.com/questions/24684806/… .
Nicola

37

Đây là một vấn đề rất thú vị mà Spring SecuritySpring Web framework không hoàn toàn nhất quán trong cách chúng xử lý phản hồi. Tôi tin rằng nó phải hỗ trợ xử lý thông báo lỗi một cách tự nhiên MessageConvertertheo cách hữu ích.

Tôi đã cố gắng tìm một cách thanh lịch để tiêm MessageConverter vào Spring Security để họ có thể bắt ngoại lệ và trả lại chúng ở định dạng phù hợp theo thương lượng nội dung . Tuy nhiên, giải pháp của tôi dưới đây không phải là thanh lịch nhưng ít nhất hãy sử dụng mã Spring.

Tôi giả sử bạn biết cách bao gồm thư viện Jackson và JAXB, nếu không thì không có điểm nào để tiếp tục. Tổng cộng có 3 bước.

Bước 1 - Tạo một lớp độc lập, lưu trữ MessageConverters

Lớp học này không chơi ảo thuật. Nó chỉ đơn giản là lưu trữ các bộ chuyển đổi thông điệp và một bộ xử lý RequestResponseBodyMethodProcessor. Điều kỳ diệu là bên trong bộ xử lý đó sẽ thực hiện tất cả công việc bao gồm đàm phán nội dung và chuyển đổi cơ quan phản hồi cho phù hợp.

public class MessageProcessor { // Any name you like
    // List of HttpMessageConverter
    private List<HttpMessageConverter<?>> messageConverters;
    // under org.springframework.web.servlet.mvc.method.annotation
    private RequestResponseBodyMethodProcessor processor;

    /**
     * Below class name are copied from the framework.
     * (And yes, they are hard-coded, too)
     */
    private static final boolean jaxb2Present =
        ClassUtils.isPresent("javax.xml.bind.Binder", MessageProcessor.class.getClassLoader());

    private static final boolean jackson2Present =
        ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", MessageProcessor.class.getClassLoader()) &&
        ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", MessageProcessor.class.getClassLoader());

    private static final boolean gsonPresent =
        ClassUtils.isPresent("com.google.gson.Gson", MessageProcessor.class.getClassLoader());

    public MessageProcessor() {
        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();

        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter());
        this.messageConverters.add(new SourceHttpMessageConverter<Source>());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

        if (jaxb2Present) {
            this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
        }
        if (jackson2Present) {
            this.messageConverters.add(new MappingJackson2HttpMessageConverter());
        }
        else if (gsonPresent) {
            this.messageConverters.add(new GsonHttpMessageConverter());
        }

        processor = new RequestResponseBodyMethodProcessor(this.messageConverters);
    }

    /**
     * This method will convert the response body to the desire format.
     */
    public void handle(Object returnValue, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        ServletWebRequest nativeRequest = new ServletWebRequest(request, response);
        processor.handleReturnValue(returnValue, null, new ModelAndViewContainer(), nativeRequest);
    }

    /**
     * @return list of message converters
     */
    public List<HttpMessageConverter<?>> getMessageConverters() {
        return messageConverters;
    }
}

Bước 2 - Tạo AuthenticationEntryPoint

Như trong nhiều hướng dẫn, lớp này rất cần thiết để triển khai xử lý lỗi tùy chỉnh.

public class CustomEntryPoint implements AuthenticationEntryPoint {
    // The class from Step 1
    private MessageProcessor processor;

    public CustomEntryPoint() {
        // It is up to you to decide when to instantiate
        processor = new MessageProcessor();
    }

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

        // This object is just like the model class, 
        // the processor will convert it to appropriate format in response body
        CustomExceptionObject returnValue = new CustomExceptionObject();
        try {
            processor.handle(returnValue, request, response);
        } catch (Exception e) {
            throw new ServletException();
        }
    }
}

Bước 3 - Đăng ký điểm vào

Như đã đề cập, tôi làm điều đó với Java Config. Tôi chỉ hiển thị cấu hình có liên quan ở đây, nên có cấu hình khác như phiên không trạng thái , v.v.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new CustomEntryPoint());
    }
}

Hãy thử với một số trường hợp xác thực không thành công, hãy nhớ tiêu đề yêu cầu phải bao gồm Chấp nhận: XXX và bạn sẽ có ngoại lệ trong JSON, XML hoặc một số định dạng khác.


1
Tôi đang cố gắng bắt InvalidGrantExceptionnhưng phiên bản của bạn CustomEntryPointkhông được gọi ra. Bất kỳ ý tưởng những gì tôi có thể bị thiếu?
hiển thị

@tên hiển thị. Tất cả các ngoại lệ xác thực không thể bị bắt AuthenticationEntryPointAccessDeniedHandlerchẳng hạn như UsernameNotFoundExceptionInvalidGrantExceptioncó thể được xử lý AuthenticationFailureHandlernhư được giải thích ở đây .
Wilson

23

Cách tốt nhất tôi đã tìm thấy là ủy quyền ngoại lệ cho HandlerExceptionResolver

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        resolver.resolveException(request, response, null, exception);
    }
}

thì bạn có thể sử dụng @ExceptionHandler để định dạng phản hồi theo cách bạn muốn.


9
Hoạt động như một sự quyến rũ. Nếu Spring gặp lỗi nói rằng có 2 định nghĩa bean cho tự động chuyển hướng, bạn phải thêm chú thích định tính: @Autowosystem @Qualifier ("handlerExceptionResolver") private HandlerExceptionResolver giải quyết;
Daividh

1
Hãy lưu ý rằng bằng cách chuyển một trình xử lý null, @ControllerAdvicesẽ không hoạt động nếu bạn đã chỉ định basePackages trên chú thích. Tôi đã phải xóa hoàn toàn điều này để cho phép trình xử lý được gọi.
Jarmex

Tại sao bạn lại cho @Component("restAuthenticationEntryPoint")? Tại sao lại cần một cái tên như restAuthenticationEntryPoint? Có phải để tránh một số va chạm tên Spring không?
theprogrammer

@Jarmex Vậy thay cho null, bạn đã vượt qua cái gì? một số loại xử lý của nó phải không? Tôi có nên chuyển một lớp đã được chú thích bằng @ControllerAdvice không? Cảm ơn
theprogrammer

@theprogrammer, tôi đã phải cấu trúc lại ứng dụng một chút để loại bỏ tham số chú thích basePackages để tránh nó - không lý tưởng!
Jarmex

5

Trong trường hợp Spring Boot và @EnableResourceServer, tương đối dễ dàng và thuận tiện để mở rộng ResourceServerConfigurerAdapterthay vì WebSecurityConfigurerAdaptertrong cấu hình Java và đăng ký một tùy chỉnh AuthenticationEntryPointbằng cách ghi đè configure(ResourceServerSecurityConfigurer resources)và sử dụngresources.authenticationEntryPoint(customAuthEntryPoint()) bên trong phương thức.

Một cái gì đó như thế này:

@Configuration
@EnableResourceServer
public class CommonSecurityConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(customAuthEntryPoint());
    }

    @Bean
    public AuthenticationEntryPoint customAuthEntryPoint(){
        return new AuthFailureHandler();
    }
}

Ngoài ra còn có một cái hay OAuth2AuthenticationEntryPointcó thể được mở rộng (vì nó chưa phải là cuối cùng) và được sử dụng lại một phần trong khi triển khai một tùy chỉnhAuthenticationEntryPoint . Đặc biệt, nó thêm tiêu đề "WWW-Authenticate" với các chi tiết liên quan đến lỗi.

Hy vọng điều này sẽ giúp một ai đó.


Tôi đang thử điều này nhưng commence()chức năng của tôi AuthenticationEntryPointkhông được gọi - tôi có thiếu thứ gì không?
hiển thị

4

Nhận câu trả lời từ @Nicola và @Victor Wing và thêm một cách chuẩn hóa hơn:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UnauthorizedErrorAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {

    private HttpMessageConverter messageConverter;

    @SuppressWarnings("unchecked")
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        MyGenericError error = new MyGenericError();
        error.setDescription(exception.getMessage());

        ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
        outputMessage.setStatusCode(HttpStatus.UNAUTHORIZED);

        messageConverter.write(error, null, outputMessage);
    }

    public void setMessageConverter(HttpMessageConverter messageConverter) {
        this.messageConverter = messageConverter;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        if (messageConverter == null) {
            throw new IllegalArgumentException("Property 'messageConverter' is required");
        }
    }

}

Bây giờ, bạn có thể đưa Jackson, Jaxb đã định cấu hình hoặc bất cứ thứ gì bạn sử dụng để chuyển đổi các phần tử phản hồi trên chú thích MVC của bạn hoặc cấu hình dựa trên XML với các trình tuần tự hóa, trình giải mã của nó, v.v.


Tôi rất mới để khởi động mùa xuân: xin vui lòng cho tôi biết "làm thế nào để vượt qua đối tượng messageConverter để authenticationEntry điểm"
Kona Suresh

Thông qua người định cư. Khi bạn sử dụng XML, bạn phải tạo một <property name="messageConverter" ref="myConverterBeanName"/>thẻ. Khi bạn sử dụng một @Configurationlớp chỉ cần sử dụng setMessageConverter()phương thức.
Gabriel Villacis

4

Chúng ta cần sử dụng HandlerExceptionResolvertrong trường hợp đó.

@Component
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    //@Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        resolver.resolveException(request, response, null, authException);
    }
}

Ngoài ra, bạn cần thêm vào lớp xử lý ngoại lệ để trả về đối tượng của bạn.

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(AuthenticationException.class)
    public GenericResponseBean handleAuthenticationException(AuthenticationException ex, HttpServletResponse response){
        GenericResponseBean genericResponseBean = GenericResponseBean.build(MessageKeys.UNAUTHORIZED);
        genericResponseBean.setError(true);
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        return genericResponseBean;
    }
}

bạn có thể gặp lỗi tại thời điểm chạy một dự án do triển khai nhiều lần HandlerExceptionResolver, Trong trường hợp đó, bạn phải thêm @Qualifier("handlerExceptionResolver")vàoHandlerExceptionResolver


GenericResponseBeanchỉ là java POJO, có thể bạn có thể tạo riêng của bạn
Vinit Solanki

2

Tôi có thể xử lý điều đó bằng cách chỉ cần ghi đè phương thức 'Xác thực không thành công' trong bộ lọc của mình. Tại đó, tôi gửi phản hồi lỗi cho máy khách với mã trạng thái HTTP mong muốn.

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException failed) throws IOException, ServletException {

    if (failed.getCause() instanceof RecordNotFoundException) {
        response.sendError((HttpServletResponse.SC_NOT_FOUND), failed.getMessage());
    }
}

1

Cập nhật: Nếu bạn thích và muốn xem mã trực tiếp, thì tôi có hai ví dụ cho bạn, một ví dụ sử dụng Spring Security tiêu chuẩn mà bạn đang tìm kiếm, một ví dụ khác sử dụng tương đương với Reactive Web và Reactive Security:
- Bình thường Web + Jwt Security
- Reactive Jwt

Cái mà tôi luôn sử dụng cho các điểm cuối dựa trên JSON của mình trông giống như sau:

@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    ObjectMapper mapper;

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthEntryPoint.class);

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e)
            throws IOException, ServletException {
        // Called when the user tries to access an endpoint which requires to be authenticated
        // we just return unauthorizaed
        logger.error("Unauthorized error. Message - {}", e.getMessage());

        ServletServerHttpResponse res = new ServletServerHttpResponse(response);
        res.setStatusCode(HttpStatus.UNAUTHORIZED);
        res.getServletResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        res.getBody().write(mapper.writeValueAsString(new ErrorResponse("You must authenticated")).getBytes());
    }
}

Đối tượng ánh xạ trở thành một bean khi bạn thêm trình khởi động web mùa xuân, nhưng tôi thích tùy chỉnh nó hơn, vì vậy đây là cách triển khai của tôi cho ObjectMapper:

  @Bean
    public Jackson2ObjectMapperBuilder objectMapperBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.modules(new JavaTimeModule());

        // for example: Use created_at instead of createdAt
        builder.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

        // skip null fields
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return builder;
    }

AuthenticationEntryPoint mặc định mà bạn đặt trong lớp WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ............
   @Autowired
    private JwtAuthEntryPoint unauthorizedHandler;
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                // .antMatchers("/api/auth**", "/api/login**", "**").permitAll()
                .anyRequest().permitAll()
                .and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


        http.headers().frameOptions().disable(); // otherwise H2 console is not available
        // There are many ways to ways of placing our Filter in a position in the chain
        // You can troubleshoot any error enabling debug(see below), it will print the chain of Filters
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
// ..........
}

1

Tùy chỉnh bộ lọc và xác định loại bất thường nào, nên có một phương pháp tốt hơn phương pháp này

public class ExceptionFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    String msg = "";
    try {
        filterChain.doFilter(request, response);
    } catch (Exception e) {
        if (e instanceof JwtException) {
            msg = e.getMessage();
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType(MediaType.APPLICATION_JSON.getType());
        response.getWriter().write(JSON.toJSONString(Resp.error(msg)));
        return;
    }
}

}


0

Tôi đang sử dụng objectMapper. Mọi Rest Service hầu hết đều hoạt động với json và trong một trong các cấu hình của bạn, bạn đã định cấu hình một trình ánh xạ đối tượng.

Code được viết bằng Kotlin, hy vọng nó sẽ ổn.

@Bean
fun objectMapper(): ObjectMapper {
    val objectMapper = ObjectMapper()
    objectMapper.registerModule(JodaModule())
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)

    return objectMapper
}

class UnauthorizedAuthenticationEntryPoint : BasicAuthenticationEntryPoint() {

    @Autowired
    lateinit var objectMapper: ObjectMapper

    @Throws(IOException::class, ServletException::class)
    override fun commence(request: HttpServletRequest, response: HttpServletResponse, authException: AuthenticationException) {
        response.addHeader("Content-Type", "application/json")
        response.status = HttpServletResponse.SC_UNAUTHORIZED

        val responseError = ResponseError(
            message = "${authException.message}",
        )

        objectMapper.writeValue(response.writer, responseError)
     }}

0

Trong ResourceServerConfigurerAdapterlớp, đoạn mã dưới đây có tác dụng với tôi. http.exceptionHandling().authenticationEntryPoint(new AuthFailureHandler()).and.csrf()..đã không làm việc. Đó là lý do tại sao tôi đã viết nó như một cuộc gọi riêng biệt.

public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.exceptionHandling().authenticationEntryPoint(new AuthFailureHandler());

        http.csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .antMatchers("/subscribers/**").authenticated()
                .antMatchers("/requests/**").authenticated();
    }

Triển khai AuthenticationEntryPoint để bắt mã thông báo hết hạn và thiếu tiêu đề ủy quyền.


public class AuthFailureHandler implements AuthenticationEntryPoint {

  @Override
  public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e)
      throws IOException, ServletException {
    httpServletResponse.setContentType("application/json");
    httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    if( e instanceof InsufficientAuthenticationException) {

      if( e.getCause() instanceof InvalidTokenException ){
        httpServletResponse.getOutputStream().println(
            "{ "
                + "\"message\": \"Token has expired\","
                + "\"type\": \"Unauthorized\","
                + "\"status\": 401"
                + "}");
      }
    }
    if( e instanceof AuthenticationCredentialsNotFoundException) {

      httpServletResponse.getOutputStream().println(
          "{ "
              + "\"message\": \"Missing Authorization Header\","
              + "\"type\": \"Unauthorized\","
              + "\"status\": 401"
              + "}");
    }

  }
}

không hoạt động .. vẫn hiển thị thông báo mặc định
aswzen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.