Как я могу обработать InvalidSignatureException при проверке JWT в Spring Boot? - PullRequest
0 голосов
/ 19 февраля 2020

Я разрабатываю свой собственный сервер аутентификации Spring Boot и сервер ресурсов, и они работают нормально. Сервер аутентификации предоставляет токен RSW6 JWS, а сервер ресурсов может проверить токен.

Я был очень счастлив и хотел бы знать, что произойдет, если я использую другую пару ключей RSA для проверки токена JWS , Вышло:

org.springframework.security.jwt.crypto.sign.InvalidSignatureException: RSA Signature did not match content
    at org.springframework.security.jwt.crypto.sign.RsaVerifier.verify(RsaVerifier.java:55)
    at org.springframework.security.jwt.JwtImpl.verifySignature(JwtHelper.java:287)
    at org.springframework.security.oauth2.provider.token.store.jwk.JwkVerifyingJwtAccessTokenConverter.decode(JwkVerifyingJwtAccessTokenConverter.java:122)
    at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.convertAccessToken(JwtTokenStore.java:88)
    at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.readAccessToken(JwtTokenStore.java:80)
    at org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore.readAccessToken(JwkTokenStore.java:212)
    at org.springframework.security.oauth2.provider.token.DefaultTokenServices.loadAuthentication(DefaultTokenServices.java:229)
    at org.springframework.security.oauth2.provider.token.DefaultTokenServices$$FastClassBySpringCGLIB$$5a1f25c.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)
    at org.springframework.security.oauth2.provider.token.DefaultTokenServices$$EnhancerBySpringCGLIB$$14463cf2.loadAuthentication(<generated>)
    at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager.authenticate(OAuth2AuthenticationManager.java:83)
    at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter(OAuth2AuthenticationProcessingFilter.java:150)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
...

и ответ <500 Internal Server Error> с телом:

<!doctype html>
<html lang="en">

<head>
    <title>HTTP Status 500 – Internal Server Error</title>
    <style type="text/css">
        h1 {
            font-family: Tahoma, Arial, sans-serif;
            color: white;
            background-color: #525D76;
            font-size: 22px;
        }

        h2 {
            font-family: Tahoma, Arial, sans-serif;
            color: white;
            background-color: #525D76;
            font-size: 16px;
        }

        h3 {
            font-family: Tahoma, Arial, sans-serif;
            color: white;
            background-color: #525D76;
            font-size: 14px;
        }

        body {
            font-family: Tahoma, Arial, sans-serif;
            color: black;
            background-color: white;
        }

        b {
            font-family: Tahoma, Arial, sans-serif;
            color: white;
            background-color: #525D76;
        }

        p {
            font-family: Tahoma, Arial, sans-serif;
            background: white;
            color: black;
            font-size: 12px;
        }

        a {
            color: black;
        }

        a.name {
            color: black;
        }

        .line {
            height: 1px;
            background-color: #525D76;
            border: none;
        }
    </style>
</head>

<body>
    <h1>HTTP Status 500 – Internal Server Error</h1>
</body>

</html>

Я хотел бы обработать эту ошибку в пользовательском JSON тело ошибки или, по крайней мере, выглядит так же, как обычное исключение AuthenticationException

например, <401 не авторизован>

{
    "error": "invalid_token",
    "error_description": "Invalid JWT/JWS: RSA Signature did not match content"
}

Мои зависимости Spring / Boot:

plugins {
    id 'org.springframework.boot' version '2.2.4.RELEASE'
    ...
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE")
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-web')
    compile("org.springframework.cloud:spring-cloud-starter-sleuth")
    compile("org.springframework.security:spring-security-jwt")
    ...
}

Что я пробовал:

  • Обрабатывать @ControllerAdvice (Из других ответов в Stackoverflow должен быть запрос, который еще не перешел в MVC, поэтому бесполезен)
  • Зарегистрируйте пользовательские AuthenticationEntryPoint до ResourceServerConfigurerAdapter.configure(HttpSecurity) (Не знаю, почему это не может помочь, но попытался)
  • Редактировать
    Попробовал предложение от @Jazzepi, Реализация HandlerExceptionResolver или расширение AbstractHandlerExceptionResolver с помощью метода:
@Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (ex instanceof InvalidSignatureException) {
            ModelAndView mav = new ModelAndView(new MappingJackson2JsonView());
            mav.addObject("key", "value");
            return mav;
        }
        return null;
    }

И затем попытался зарегистрироваться через WebMvcConfigurator.extendHandlerExceptionResolvers(List<HandleExceptionResolvers>) (Это не может помочь, все равно выведите тот же ответ, что и выше)


Редактировать:

Как создать и декодировать токен?
В точности следует этому уроку: https://www.baeldung.com/spring-security-oauth2-jws-jwk

Как воспроизвести эту ситуацию?

  1. Запустить сервер аутентификации и ресурсов.
  2. Получить токен с сервера аутентификации и один раз используйте токен на сервере ресурсов, чтобы кеш сервера ресурсов опубликовал ключ publi c в локальном
  3. Измените файл хранилища ключей на сервере аутентификации и перезапустите
  4. Получить новый токен с перезапущенного сервера аутентификации
  5. Использование нового токена на сервере ресурсов

1 Ответ

0 голосов
/ 19 февраля 2020

Spring Boot поставляется с парой классов, которые отображают исключения для методов, запускаемых при возникновении этих исключений.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.html#addDefaultHandlerExceptionResolvers - java .util.List-

Регистрирует HandlerExceptionResolverComposite с этой цепочкой определителей исключений:

ExceptionHandlerExceptionResolver для обработки исключений с помощью методов ExceptionHandler.

ResponseStatusExceptionResolver для исключений, аннотированных

1014 * *. DefaultHandlerExceptionResolver для разрешения известных типов исключений Spring

Я думаю, что вы хотите создать свой собственный обработчик исключений. Это даст вам возможность выполнить любой код, который вы захотите, в ответ на указанное исключение c. Вероятно, хотите реализовать этот интерфейс. Изучите документы, потому что Spring предоставляет широкий спектр абстрактных классов, которые вы можете расширить, что облегчит вашу жизнь вместо того, чтобы писать с интерфейса с нуля.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerExceptionResolver.html

Наконец, вам нужно зарегистрировать ваш обработчик в Spring. Это выглядит как хороший способ сделать это.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html#extendHandlerExceptionResolvers - java .util.List-

Удачи!

Кому Устранение неполадок Я бы установил точку останова в org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java для doResolveException и посмотрел, перехватывает ли она и обрабатывает ли ваше исключение там (я думаю, что это так).

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

@ Order (Ordered.HIGHEST_PRECEDENCE)

Вы также, вероятно, хотите, чтобы ваш обработчик используйте response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage()); sendError вместо того, чтобы возиться с материалом ModelAndView (). Это для того, чтобы сообщить Spring, на какую веб-страницу перенаправить. Посмотрите на отдельные методы обработчика по умолчанию, чтобы получить представление о различных способах обработки ошибок.

...