有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java验证JsonWebToken签名

我收到一份JWT,想核实它的签名。 它不是加密的,是based64编码的,并使用HmacSha256签名。 上面签着一个我知道的秘密

我似乎找不到任何不使用https://jwt.io/上列出的第三方库(即JavaJWT、jpose4j等)就如何验证签名的示例

有可能这样做吗

到目前为止,我所拥有的:

private boolean validateSignature( String header, String data, String signature, String secretKey ) throws Exception {
    Base64 base64 = new Base64( true );
    SecretKeySpec secret = new SecretKeySpec( secretKey.getBytes(), "HmacSHA256" );
    Mac mac = Mac.getInstance( "HmacSHA256" );
    mac.init( secret );

    byte[] hmacDataBytes = mac.doFinal( data.getBytes( StandardCharsets.UTF_8.name()) );
    String hmacData = new String( hmacDataBytes );

    return hmacData.equals( signature ); // Compare signatures here...
}

基于@pedrofb和@jps答案,以下是解决方案:

private boolean validToken( String authToken, String key ) throws Exception {
    String[] token = authToken.split( "\\." );
    String header = token[0];
    String payload = token[1];
    String originalSignature = token[2];

    SecretKeySpec secret = new SecretKeySpec( Base64.getDecoder().decode( key ), ALGORITM_HMACSHA256 );
    Mac mac = Mac.getInstance( ALGORITM_HMACSHA256 );
    mac.init( secret );

    StringBuilder headerAndPayload = new StringBuilder( header ).append( "." ).append( payload );

    byte[] signatureBytes = mac.doFinal( headerAndPayload.toString().getBytes( StandardCharsets.UTF_8.name() ) );
    String calculatedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString( signatureBytes );

    return calculatedSignature.equals( originalSignature );
}

共 (2) 个答案

  1. # 1 楼答案

    要验证签名,需要获取Base64Url编码的头和有效负载,计算HMACSha256哈希值和密码,Base64Url编码结果并将其与原始签名进行比较。当然,HMACSha256算法和Base64#Url编码需要lib,但不需要特定的JWT lib

    用伪代码编写,以显示原理:

    hash = HmacSHA256(header + "." + payload , secret)
    

    这里header是Base64Url编码的头,payload是Base64Url编码的负载

    result = Base64UrlEncode(hash)
    

    result现在可以与原始签名进行比较

    在另一个answer中,我用节点描述了这个过程。js和在线工具

  2. # 2 楼答案

    JWT有三个用点分隔的base64url编码的部分

    header.payload.signature
    

    签名是在header.payload上计算的

    假设您的方法接收base64url中的元素,您需要在header + "." + data上计算HMAC,将结果编码为base64url,并与签名字段进行比较

    大概是这样的:

    private boolean validateSignature( String header, String data, String signature, String secretKey ) throws Exception {
    
        SecretKeySpec secret = new SecretKeySpec( secretKey.getBytes(), "HmacSHA256" );
        Mac mac = Mac.getInstance( "HmacSHA256" );
        mac.init( secret );
    
        String body = header + "." + data;
        byte[] hmacDataBytes = mac.doFinal( body.getBytes( StandardCharsets.UTF_8.name()) );
        String hmacData = Base64.getUrlEncoder().encodeToString( hmacDataBytes );
    
        return hmacData.equals( signature ); // Compare signatures here...
    }