0

我需要在使用 Java 中的 CAS 构建的 SSO 中添加 PHP 应用程序。用户身份验证后,SSO 将凭据发送到 PHP 应用程序,并使用以下代码构建令牌:

public function getToken(Signer $signer = null, Key $key = null)
    {
        $signer = $signer ?: $this->signer;
        $key = $key ?: $this->key;

        if ($signer instanceof Signer) {
            $signer->modifyHeader($this->headers);
        }

        $payload = [
            $this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->headers)),
            $this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->claims))
        ];

        $signature = $this->createSignature($payload, $signer, $key);

        if ($signature !== null) {
            $payload[] = $this->encoder->base64UrlEncode($signature);
        }

        return new Token($this->headers, $this->claims, $signature , $payload);
    }

    private function createSignature(array $payload, Signer $signer = null, Key $key = null)
    {
        if ($signer === null || $key === null) {
            return null;
        }
        return $signer->sign(implode('.', $payload), $key);
    }

因此,我尝试使用 java 验证生成的令牌,如下所示:

 public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException e) {
            log.info("Invalid JWT signature.");
            log.trace("Invalid JWT signature trace: {}", e);
            e.printStackTrace();
        }
        ....
    }

为了验证签名,jjwt 拆分了令牌的 3 个部分,并尝试使用令牌标头中提供的算法对前 2 个部分进行签名。此步骤与创建令牌时用于创建令牌的签名相同。理论上,在创建和验证这两个步骤中使用相同的算法、paylod 和 secret,签名应该是相同的。但它不会发生。抛出以下异常:

io.jsonwebtoken.SignatureException:JWT 签名与本地计算的签名不匹配。JWT 有效性不能被断言,也不应该被信任。

4

1 回答 1

2

我会回答我自己的问题。jjwt 需要一个 base64 加密的秘密。但是在我的 java 代码中,在将其设置在解析器中之前,我没有对其进行编码。

这是 jjwt 验证令牌签名的方式:

    public boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature) {

        byte[] data = jwtWithoutSignature.getBytes(US_ASCII);

        byte[] signature = TextCodec.BASE64URL.decode(base64UrlEncodedSignature);

        return this.signatureValidator.isValid(data, signature);
    }

我在我的 java 代码中所做的更改:

    secretKey = TextCodec.BASE64URL.encode(secret);
    Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken)
于 2019-08-13T12:43:57.013 回答