Spring JWT 签名验证失败

Posted

技术标签:

【中文标题】Spring JWT 签名验证失败【英文标题】:Spring JWT signature Validation fails 【发布时间】:2018-04-30 10:47:40 【问题描述】:

我正在使用 Spring Cloud、oauth 和 JWT 构建微服务应用程序。我的 Oauth2 服务器生成 JWT 令牌,但是当我尝试验证网关中的令牌(使用 ZUUL 实现)时,我遇到了错误

能否请您告诉我出了什么问题以及可能的解决方案。 我使用的是 Spring 4.3、Spring boot 1.5.8、Spring cloud Dalston.SR4

org.springframework.security.jwt.crypto.sign.InvalidSignatureException: Calculated signature did not match actual value
    at org.springframework.security.jwt.crypto.sign.MacSigner.verify(MacSigner.java:62) ~[spring-security-jwt-1.0.8.RELEASE.jar:na]
    at org.springframework.security.jwt.JwtImpl.verifySignature(JwtHelper.java:287) ~[spring-security-jwt-1.0.8.RELEASE.jar:na]
    at org.springframework.security.jwt.JwtHelper.decodeAndVerify(JwtHelper.java:77) ~[spring-security-jwt-1.0.8.RELEASE.jar:na]
    at com.debopam.gateway.filter.CustomPostZuulFilter.run(CustomPostZuulFilter.java:57) ~[classes/:na]
    at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) [zuul-core-1.3.0.jar:1.3.0]
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193) [zuul-core-1.3.0.jar:1.3.0]
    at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157) [zuul-core-1.3.0.jar:1.3.0]
    at com.netflix.zuul.FilterProcessor.postRoute(FilterProcessor.java:92) [zuul-core-1.3.0.jar:1.3.0]
    at com.netflix.zuul.ZuulRunner.postRoute(ZuulRunner.java:87) [zuul-core-1.3.0.jar:1.3.0]

我在身份验证服务器和网关服务器中都使用了签名密钥 12345AsDfG

下面是代码sn-p 身份验证服务器

@Configuration
public class JWTTokenStoreConfig 

    @Autowired
    private ServiceConfig serviceConfig;

    @Bean
    public TokenStore tokenStore() 
        return new JwtTokenStore(jwtAccessTokenConverter());
    

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() 
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setAccessTokenValiditySeconds(60*30);
        return defaultTokenServices;
    


    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() 
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(serviceConfig.getJwtSigningKey());
        return converter;
    

    @Bean
    public TokenEnhancer jwtTokenEnhancer() 
        return new JWTTokenEnhancer();
    



@Configuration
public class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter 

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private DefaultTokenServices tokenServices;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private TokenEnhancer jwtTokenEnhancer;


    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
    
        //oauthServer.checkTokenAccess("permitAll()");    

        oauthServer
        .tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
        .checkTokenAccess("permitAll()");
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter));

        endpoints.tokenStore(tokenStore)                             //JWT
                .accessTokenConverter(jwtAccessTokenConverter)       //JWT
                .tokenEnhancer(tokenEnhancerChain)                   //JWT
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);


    



    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 

        clients.inMemory()
                .withClient("uiapp")
                .secret("secret")
                .authorizedGrantTypes("refresh_token", "password", "client_credentials")
                .scopes("webclient", "mobileclient");
    

网关应用程序中,我使用下面的代码来验证令牌

@Override
public Object run() 
    RequestContext ctx = RequestContext.getCurrentContext();
    try 
        InputStream is = ctx.getResponseDataStream();
        String responseBody = IOUtils.toString(is);

        if (StringUtils.hasText(responseBody) 
                && responseBody.contains("access_token")) 
            Map<String, Object> responseMap = objectMapper.readValue(
                    responseBody, new TypeReference<Map<String, Object>>() );
            String accesToken = responseMap.get("access_token").toString();

            Jwt jwt = JwtHelper.decodeAndVerify(accesToken, new MacSigner(serviceConfig.getJwtSigningKey()));

            System.out.println(jwt.getClaims());
            //System.out.println(jwt.getBody());

        
        ctx.setResponseBody(responseBody);
     catch (Exception e) 
        logger.error("Error occured in zuul post filter", e);
    
    return null;

【问题讨论】:

我查看了 spring oauth 中的其他实现和测试,但一无所获。我会调试它。到达时令牌的格式是否正确?和生产的一样吗?两端的key一样吗? 抱歉,服务之间存在密钥不匹配。 【参考方案1】:

服务之间存在签名密钥不匹配。

【讨论】:

以上是关于Spring JWT 签名验证失败的主要内容,如果未能解决你的问题,请参考以下文章

JWT/OAuth 令牌签名验证失败

使用 PHP 的 JWT“签名验证失败”

使用 PyJWT 的 Jwt 解码引发签名验证失败

CAS 6.0 和 Spring Security:服务票证验证时 JWT 配置失败

ASP.NET JWT:签名验证失败。没有提供安全密钥来验证签名

PyJWT 引发签名验证失败