直接贴代码,其实就只是需要封装两个工具类,直接用就没问题了
Controller中loginApple方法
@PostMapping("/login")
public Response loginApple(@RequestBody AppleLoginDTO dto){
String appleUserId;
String email;
switch (dto.getSigninMethod()){
case GOOGLE:
GoogleAuthResult googleResult = GoogleAuthVerifier.verify(dto.getIdentityToken());
appleUserId = googleResult.getSub();
email = googleResult.getEmail();
break;
case APPLEID:
AppleAuthResult verify = AppleAuthVerifier.verify(dto.getIdentityToken(), dto.getBundleId());
appleUserId = verify.getSub();
email = verify.getEmail();
break;
default:
return null;
}
User user = userLoginService.findByAppleSub(appleUserId);
if(user == null){
user = userLoginService.createUser(appleUserId,email);
}
UserLoginVO result = new UserLoginVO(SignType.SIGNIN);
result.setUser(user);
result.setToken(UserTokenUtils.create(
new UserToken(user.getId())
));
return SingleResponse.ok(result);
}
AppleLoginDTO
@Data
public class AppleLoginDTO {
private String identityToken;
private String bundleId;
private SigninMethod signinMethod;
}
GoogleAuthVerifier
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class GoogleAuthVerifier {
private static final String GOOGLE_AUTH_URL = "https://oauth2.googleapis.com/tokeninfo";
public static GoogleAuthResult verify(String accessToken) {
GoogleAuthResult result = null;
HttpUrl url = HttpUrl.parse(GOOGLE_AUTH_URL).newBuilder()//
.addQueryParameter("id_token", accessToken)//
.build();
final Request request = new Request.Builder() //
.url(url) //
.get() //
.build(); //
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
result = GsonUtils.fromJson(response.body().string(), GoogleAuthResult.class);
} catch (Exception e) {
throw new SvcException(e.getMessage());
}
return result;
}
}
AppleAuthVerifier
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class AppleAuthVerifier {
private static final String APPLE_AUTH_KEYS_URL = "https://appleid.apple.com/auth/keys";
private static final String ISSUER = "https://appleid.apple.com";
private static Map<String, AppleAuthKey> appleKeyMap;
/**
* 获取苹果验证秘钥
*
* @return
*/
private static Map<String, AppleAuthKey> getAppleKeys() {
if (MapUtils.isEmpty(appleKeyMap)) {
Request request = new Request.Builder()//
.url(APPLE_AUTH_KEYS_URL) //
.get() //
.build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> keysMap = GsonUtils.fromJson(response.body().string(), type);
type = new TypeToken<List<AppleAuthKey>>() {}.getType();
List<AppleAuthKey> appleKeyList = GsonUtils.fromJson(GsonUtils.toJson(keysMap.get("keys")), type);
appleKeyMap = appleKeyList.stream().collect(Collectors.toMap(AppleAuthKey::getKid, v -> v));
} catch (IOException e) {
throw new AppleAuthFailedException(e.getMessage());
}
}
return appleKeyMap;
}
/**
* 获取公钥
*
* @param kid
* @return
*/
private static RSAPublicKey getPublicKey(String kid) {
try {
AppleAuthKey appleKey = getAppleKeys().get(kid);
BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(appleKey.getN()));
BigInteger publicExponent = new BigInteger(1, Base64.getDecoder().decode(appleKey.getE()));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance(appleKey.getKty());// 目前kty均为 "RSA"
return (RSAPublicKey)kf.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
log.error("Decode publicKey failed: {}", e.getMessage(), e);
}
return null;
}
/**
* 解码token
*
* @param identityToken
* @return
*/
private static AppleAuthTokenHeader decodeTokenHeader(String identityToken) {
String[] arr = identityToken.split("\\.");
String deHeader = new String(Base64.getDecoder().decode(arr[0]));
return GsonUtils.fromJson(deHeader, AppleAuthTokenHeader.class);
}
public static AppleAuthResult verify(String identityToken, String bundleId) {
AppleAuthTokenHeader header = decodeTokenHeader(identityToken);
Algorithm algorithm = Algorithm.RSA256(getPublicKey(header.getKid()), null);
JWTVerifier verifier = JWT.require(algorithm)//
.withIssuer(ISSUER) //
.withAudience(bundleId) //
.build();
DecodedJWT decodedJWT = verifier.verify(identityToken);
final Map<String, Object> maps = Maps.newHashMap();
decodedJWT.getClaims().entrySet().forEach(item -> maps.put(item.getKey(), item.getValue().as(Object.class)));
return GsonUtils.fromJson(GsonUtils.toJson(maps), AppleAuthResult.class);
}
}
直接拿着用就没问题了