Spring Boot Rest Controller: вернуть ошибку по умолчанию JSON - PullRequest
0 голосов
/ 08 мая 2019

В моем API я люблю защищать конечные точки сведений о пользователе, чтобы обычные вошедшие в систему пользователи могли получить доступ только к своему профилю пользователя. Для этого я пишу контроллер:

@RequestMapping(value = URL_USER + "/{id}", method = RequestMethod.GET)
@ResponseBody
public PersistentEntityResource get(PersistentEntityResourceAssembler persistentEntityResourceAssembler, @PathVariable Long id) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    ApplicationUser loggedInUser = applicationUserService.findByUsername(authentication.getName());
    ApplicationUser applicationUser = applicationUserService.findById(id);

    if (applicationUser.getId().equals(loggedInUser.getId())) {
        return persistentEntityResourceAssembler.toFullResource(applicationUser);
    }

    throw new IllegalAccessException();
} 

Вместо того, чтобы вызвать исключение, которое приводит к InternalServerExcetption, мне нравится возвращать стандартную ошибку весенней загрузки json, как показано ниже:

{
    "timestamp": "2019-05-08T11:42:23.064+0000",
    "status": 403,
    "error": "Forbidden",
    "message": "Access Denied",
    "path": "/user/2"
}

Я бы предпочел решение, которое подходит и для других Erros, таких как 404. Какой самый простой способ достичь этой цели?

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

После некоторых исследований я нашел решение, которое выглядит довольно элегантно:

Метод RestController выглядит так:

@RequestMapping(value = URL_USER + "/{id}", method = RequestMethod.GET)
@ResponseBody
public PersistentEntityResource get(PersistentEntityResourceAssembler persistentEntityResourceAssembler, @PathVariable Long id) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    ApplicationUser loggedInUser = applicationUserService.findByUsername(authentication.getName());
    ApplicationUser applicationUser = applicationUserService.findById(id);

    if (applicationUser.getId().equals(loggedInUser.getId())) {
        return persistentEntityResourceAssembler.toFullResource(applicationUser);
    }

    throw new ForbiddenRequestException("Access not allowed");
}

Дополнительно я реализовал класс ForbiddenRequestException:

@ResponseStatus(value = HttpStatus.FORBIDDEN)
public class ForbiddenRequestException extends RuntimeException {
    public ForbiddenRequestException(String message) {
        super(message);
    }
}

И, по крайней мере, удалить trace из JSON, установив server.error.include-stacktrace=never в свойствах, это не может быть идеальным, но я думаю, что на производстве вам все равно следует это сделать.

0 голосов
/ 08 мая 2019

Вы можете использовать ниже методы для того же

public class FooController{

    //...
    @ExceptionHandler({ CustomException1.class, CustomException2.class })
    public String handleException() {
        return "the intended body";
    }
}

В качестве альтернативы вы можете использовать эту логику в качестве обработчика глобальных исключений, используя @ControllerAdvice

@ControllerAdvice
public class RestResponseEntityExceptionHandler
        extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value
            = { IllegalArgumentException.class, IllegalStateException.class })
    protected ResponseEntity<Object> handleConflict(
            RuntimeException ex, WebRequest request) {
        String bodyOfResponse = "This should be application specific";
        return handleExceptionInternal(ex, bodyOfResponse,
                new HttpHeaders(), HttpStatus.CONFLICT, request);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...