[英]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.