firebase |使用第三方JWT库验证ID令牌

时间:2016-08-30 08:08:07

标签: java firebase jwt firebase-authentication google-authentication

尝试使用jjwt验证firebase id令牌。使用GoogleCredential类来提取私钥。但我不确定这是否正确。收到错误:JWT signature does not match locally computed signature.我应该在服务帐户json中使用私钥吗?也许我误解了... 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;
    }

}

2 个答案:

答案 0 :(得分:2)

你在正确的路线上!在创建要发送到Google / Firebase的JWT时,会使用服务帐户中的密钥。你真的不想把它放在你的APK中,因为任何恶意的个人都可以窃取它并用它来创建ID令牌!

当您从Firebase验证令牌时,您需要检查Firebase自己的密钥 - 幸运的是,这些是公开的!您可以从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com抓取它们 - 它们每隔几个小时轮换一次。如果你查看该文件,你会发现它是一个JSON字典,如下所示:

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

此处的关键是ID令牌JWT标头中的kid字段 - 它对应于令牌签名的密钥,这意味着对应的证书可用于验证签名。

查看validating ID tokens的(服务器端)文档了解更多信息。

答案 1 :(得分:1)

使用自定义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;
    }

}