简体   繁体   English

火力基地| 使用第三方JWT库验证ID令牌

[英]firebase | Verify ID tokens using a third-party JWT library

Attempting to validate firebase id tokens using jjwt. 尝试使用jjwt验证Firebase ID令牌。 Using GoogleCredential class to pull the private key. 使用GoogleCredential类提取私钥。 But I'm not sure if that's correct. 但我不确定这是否正确。 Receiving an error: JWT signature does not match locally computed signature. 收到错误: JWT signature does not match locally computed signature. Am I supposed to be using the private key here from service account json? 我应该在这里使用服务帐户json中的私钥吗? Maybe I'm misunderstanding what ...setSigningKey(...) takes in. 也许我误会了... setSigningKey(...)的含义。

@Service
public class FirebaseAuthVerifier implements AuthVerifier {

    private static final Logger logger = LoggerFactory.getLogger(FirebaseAuthVerifier.class);

    @Autowired
    private FirebaseProperties fbProps;

    public boolean verify(AuthToken token) throws GeneralSecurityException, IOException {
        // get google credential
        InputStream stream = new FileInputStream("src/main/resources/service-account.json");
        ByteArrayOutputStream streamCopy = new ByteArrayOutputStream();
        ByteStreams.copy(stream, streamCopy);
        stream.close();

        GoogleCredential gc = GoogleCredential.fromStream(
                new ByteArrayInputStream(streamCopy.toByteArray()),
                new NetHttpTransport(),
                GsonFactory.getDefaultInstance());

        try {
            Jwts.parser().setSigningKey(gc.getServiceAccountPrivateKey()).parse(token.getTokenId());
        } catch(Exception e) {
            // log
            logger.info("Firebase auth token verification error: ");
            logger.info(e.getMessage());
            // claims may have been tampered with
            return false;
        }

        return true;
    }

}

You're on the right lines! 您说对了! The key from the service account is used when creating JWTs to send to Google/Firebase. 创建JWT发送到Google / Firebase时,将使用服务帐户中的密钥。 You really don't want to put that in your APK, as any malicious individual could steal it and use it to create ID tokens as you! 您确实不希望将其放入APK中,因为任何恶意个人都可以窃取它,并像您一样使用它来创建ID令牌!

When you're validating a token from Firebase, you need to check Firebase's own keys - luckily, these are public! 当您从Firebase验证令牌时,您需要检查Firebase自己的密钥-幸运的是,这些是公开的! You can grab them from https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com - they rotate every few hours. 您可以从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com上获取它们-它们每隔几个小时旋转一次。 If you look in that file you'll see it's a JSON dictionary, like this: 如果您查看该文件,将会看到它是一个JSON字典,如下所示:

"8226146523a1b8894ba03ad525667b9475d393f5": "---CERT---",

The key in this is the kid field in the header of the ID token JWT - it corresponds to the key the token was signed with, meaning the cert that corresponds can be used to verify the signature. 其中的密钥是ID令牌JWT标题中的kid字段-它对应于使用令牌进行签名的密钥,这意味着可以使用对应的证书来验证签名。

Take a look at the (server side) docs for validating ID tokens for more. 看看(服务器端)文档以了解更多有关ID令牌的信息。

Using custom jwt id token validation 使用自定义的jwt id令牌验证

@Service
public class FirebaseAuthVerifier implements AuthVerifier {

    private static final Logger logger = LoggerFactory.getLogger(FirebaseAuthVerifier.class);
    private static final String pubKeyUrl = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";

    /**
     *
     * @param token
     * @return
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public boolean verify(AuthToken token) throws GeneralSecurityException, IOException {
        // get public keys
        JsonObject publicKeys = getPublicKeysJson();

        // verify count
        int size = publicKeys.entrySet().size();
        int count = 0;

        // get json object as map
        // loop map of keys finding one that verifies
        for (Map.Entry<String, JsonElement> entry: publicKeys.entrySet()) {
            // log
            logger.info("attempting jwt id token validation with: ");

            try {
                // trying next key
                count++;

                // get public key
                PublicKey publicKey = getPublicKey(entry);

                // validate claim set
                Jwts.parser().setSigningKey(publicKey).parse(token.getTokenId());

                // success, we can return
                return true;
            } catch(Exception e) {
                // log
                logger.info("Firebase id token verification error: ");
                logger.info(e.getMessage());
                // claims may have been tampered with
                // if this is the last key, return false
                if (count == size) {
                    return false;
                }
            }
        }

        // no jwt exceptions
        return true;
    }

    /**
     *
     * @param entry
     * @return
     * @throws GeneralSecurityException
     */
    private PublicKey getPublicKey(Map.Entry<String, JsonElement> entry) throws GeneralSecurityException, IOException {
        String publicKeyPem = entry.getValue().getAsString()
                .replaceAll("-----BEGIN (.*)-----", "")
                .replaceAll("-----END (.*)----", "")
                .replaceAll("\r\n", "")
                .replaceAll("\n", "")
                .trim();

        logger.info(publicKeyPem);

        // generate x509 cert
        InputStream inputStream = new ByteArrayInputStream(entry.getValue().getAsString().getBytes("UTF-8"));
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate)cf.generateCertificate(inputStream);

        return cert.getPublicKey();
    }

    /**
     *
     * @return
     * @throws IOException
     */
    private JsonObject getPublicKeysJson() throws IOException {
        // get public keys
        URI uri = URI.create(pubKeyUrl);
        GenericUrl url = new GenericUrl(uri);
        HttpTransport http = new NetHttpTransport();
        HttpResponse response = http.createRequestFactory().buildGetRequest(url).execute();

        // store json from request
        String json = response.parseAsString();
        // disconnect
        response.disconnect();

        // parse json to object
        JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();

        return jsonObject;
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM