|
@@ -0,0 +1,98 @@
|
|
|
+package com.ruoyi.generator.util;
|
|
|
+
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
+import com.alibaba.fastjson2.JSONArray;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.auth0.jwk.Jwk;
|
|
|
+import io.jsonwebtoken.*;
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
+
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.PublicKey;
|
|
|
+import java.util.Base64;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Classname IOSToeknUtils
|
|
|
+ * @Description IOS token操作工具
|
|
|
+ * @Date 2023/03/23
|
|
|
+ * @Created by Goden
|
|
|
+ */
|
|
|
+public class IOSToeknUtils {
|
|
|
+
|
|
|
+ private final static String authUrl = "https://appleid.apple.com/auth/keys";
|
|
|
+
|
|
|
+ private final static String authIss = "https://appleid.apple.com";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解码identityToken
|
|
|
+ * @param identityToken
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static JSONObject parserIdentityToken(String identityToken) {
|
|
|
+ String[] arr = identityToken.split("\\.");
|
|
|
+
|
|
|
+ String firstDate = new String(Base64.getDecoder().decode(arr[0]), StandardCharsets.UTF_8);
|
|
|
+ String decode = new String(Base64.getDecoder().decode(arr[1]), StandardCharsets.UTF_8);
|
|
|
+ JSONObject claimObj = JSON.parseObject(decode);
|
|
|
+ // 将第一部分获取到的kid放入消息体中,方便后续匹配对应的公钥使用
|
|
|
+ claimObj.put("kid", JSONObject.parseObject(firstDate).get("kid"));
|
|
|
+ return claimObj;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据kid获取对应的苹果公钥
|
|
|
+ * @param kid
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static PublicKey getPublicKey(String kid) {
|
|
|
+ try {
|
|
|
+ RestTemplate restTemplate = new RestTemplate();
|
|
|
+ JSONObject data = restTemplate.getForObject(authUrl, JSONObject.class);
|
|
|
+ assert data != null;
|
|
|
+ JSONArray jsonArray = data.getJSONArray("keys");
|
|
|
+ for (Object obj : jsonArray) {
|
|
|
+ Map json = ((Map) obj);
|
|
|
+ // 获取kid对应的公钥
|
|
|
+ if (json.get("kid").equals(kid)) {
|
|
|
+ Jwk jwa = Jwk.fromValues(json);
|
|
|
+ return jwa.getPublicKey();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对前端传来的identityToken进行验证
|
|
|
+ *
|
|
|
+ * @param identityToken
|
|
|
+ * @param jsonObject
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static Boolean verifyExc(String identityToken, JSONObject jsonObject) throws Exception {
|
|
|
+ String kid = (String) jsonObject.get("kid");
|
|
|
+ PublicKey publicKey = getPublicKey(kid);
|
|
|
+
|
|
|
+ JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
|
|
|
+ jwtParser.requireIssuer(authIss);
|
|
|
+ jwtParser.requireAudience((String) jsonObject.get("aud"));
|
|
|
+ jwtParser.requireSubject((String) jsonObject.get("sub"));
|
|
|
+ try {
|
|
|
+ Jws<Claims> claim = jwtParser.parseClaimsJws(identityToken);
|
|
|
+ if (claim != null && claim.getBody().containsKey("auth_time")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ } catch (ExpiredJwtException e) {
|
|
|
+ return false;
|
|
|
+ } catch (Exception e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|