业务上需要使用gamecenter进行登录,官方文档说的比较简单,也没有示例代码可以看。网上找一通也没发现有java的实现,所以只能根据文档自己敲代码了。
下面给出官方文档:
https://developer.apple.com/documentation/gamekit/gklocalplayer/1515407-generateidentityverificationsign#discussion
关键就在于下面这段:
客户端传到后端的参数有publicKeyURL、signature、timestamp、playerID、bundleID、salt。
我们需要访问publicKeyUrl,获得公钥。并通过公钥对客户端的数据进行校验,校验通过则合法。
关键是第6点,我们需要把这些参数的字节进行拼接(一开始我直接用字符串拼接,怎么也验证不了),salt需要先进行base64decode。由于java本身就是大端的,所以timestamp直接用就行了。
代码实现
拼接第6步代码如下,获得字节数组:
public static byte[] concatContent(String playerId, String bundleId, long timestamp, String salt)
throws IOException {
return Bytes.concat(playerId.getBytes(Charsets.UTF_8), bundleId.getBytes(Charsets.UTF_8), toBigEndian(timestamp) ,
Base64.decodeBase64(salt));
}
private static byte[] toBigEndian(long value){
byte[] buffer = new byte[8];
for (int i = 0; i < 8; i++) {
buffer[7 - i] = (byte)(value & 0xff);
value = value >> 8;
}
return buffer;
}
验证代码如下:
/**
*
* @param publicKeyInput 访问publicKeyURL获得的字节流
* @param sign 客户端穿过来的sign,需要先进行base64decode
* @param original concatContent方法获得的字节数组
* @return
*/
public static boolean verifySign(InputStream publicKeyInputstream, byte[] sign, byte[] content) {
try {
CertificateFactory cf = CertificateFactory.getInstance("x.509");
X509Certificate cer = (X509Certificate)cf.generateCertificate(publicKeyInputstream);
cer.checkValidity();
PublicKey publicKey = cer.getPublicKey();
Signature signature = Signature.getInstance(cer.getSigAlgName());
signature .initVerify(publicKey);
signature .update(content);
return signature.verify(sign);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
main方法测试:
public static void main(String args[]){
String playerId = "xxxx";
String publicKeyUrl = "https://static.gc.apple.com/public-key/gc-prod-3.cer";
String bundleId = "com.xxx.xxx.game";
long timestamp = 1231231232L;
String salt = "d0xRFw==";
String sign = "augUgRE/INZLLARzyFe3/HoB9fA5IrxdmFUsq";
byte[] data = concatSignature(playerId , bundleId, timestamp, salt);
byte[] signBytes = Base64.decodeBase64(sign);
InputStream publicKeyInputStream = HttpHelper.get(publicKeyUrl);
boolean result = verifySign(publicKeyInputStream , signBytes, data);
System.out.println(result);
}