在 Spring Boot 中验证 JWT 时如何处理 InvalidSignatureException?
Posted
技术标签:
【中文标题】在 Spring Boot 中验证 JWT 时如何处理 InvalidSignatureException?【英文标题】:How can I handle InvalidSignatureException while validating JWT in Spring Boot? 【发布时间】:2020-06-03 20:54:19 【问题描述】:我正在开发自己的Spring Boot身份验证服务器和资源服务器,它们工作正常。 身份验证服务器提供 RS256 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)
...
响应是 正文:
<!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 相同
例如
"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
中处理(从***的其他答案来看,应该是请求还没有传入MVC,所以没用)
通过ResourceServerConfigurerAdapter.configure(HttpSecurity)
注册自定义AuthenticationEntryPoint
(不知道为什么没用,试过了)
编辑
尝试了@Jazzepi 的建议,Implementing HandlerExceptionResolver
or extends AbstractHandlerExceptionResolver
with method:
@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
如何重演这种情况?
-
启动身份验证和资源服务器。
从认证服务器获取token,在资源服务器中使用一次token,使资源服务器将公钥缓存在本地
更改授权服务器中的密钥库文件并重新启动
从重新启动的身份验证服务器获取新令牌
在资源服务器中使用新令牌
【问题讨论】:
请添加有关如何构建和解码令牌的代码 感谢您的回复。已更新问题。 你弄明白了吗?我有同样的情况,exceptionHandler 将其作为 RuntimeException 处理,状态为 500 :( 【参考方案1】: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 用于注释的异常 响应状态。
DefaultHandlerExceptionResolver 用于解决已知的 Spring 异常 类型
我认为您想创建自己的异常处理程序。它会让你有机会运行你想要的任何代码来响应你的特定异常。大概是想实现这个接口。不过请查看文档,因为 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 重定向到哪个网页。查看默认处理程序的各个方法,以了解处理错误的不同方式。
【讨论】:
感谢您的帮助!但是好像不行,请参考编辑过的问题 @user2602850 编辑了一些故障排除建议以上是关于在 Spring Boot 中验证 JWT 时如何处理 InvalidSignatureException?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Boot jwt 将身份验证系统连接到 React.js
Spring Boot OAuth2 资源服务器:库如何在没有公钥的情况下验证 JWT 令牌?
Spring boot + JWT 实现安全验证 ---auth0.jwt
Spring Boot OAuth2:从 cookie 中提取 JWT 进行身份验证