1.复制工具类
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.auth0.jwk.Jwk; import io.jsonwebtoken.*; import org.apache.commons.codec.binary.Base64; import org.springframework.web.client.RestTemplate; import java.security.PublicKey; public class AppleUtil { /** * 获取苹果的公钥 * @return * @throws Exception */ private static JSONArray getAuthKeys() throws Exception { String url = "https://appleid.apple.com/auth/keys"; RestTemplate restTemplate = new RestTemplate(); JSONObject json = restTemplate.getForObject(url,JSONObject.class); JSONArray arr = json.getJSONArray("keys"); return arr; } public static Boolean verify(String jwt) throws Exception{ JSONArray arr = getAuthKeys(); if(arr == null){ return false; } JSONObject authKey = null; //先取苹果第一个key进行校验 authKey = JSONObject.parseObject(arr.getString(0)); if(verifyExc(jwt, authKey)){ return true; }else{ //再取第二个key校验 authKey = JSONObject.parseObject(arr.getString(1)); return verifyExc(jwt, authKey); } } /** * 对前端传来的identityToken进行验证 * @param jwt 对应前端传来的 identityToken * @param authKey 苹果的公钥 authKey * @return * @throws Exception */ public static Boolean verifyExc(String jwt, JSONObject authKey) throws Exception { Jwk jwa = Jwk.fromValues(authKey); PublicKey publicKey = jwa.getPublicKey(); String aud = ""; String sub = ""; if (jwt.split("\.").length > 1) { String claim = new String(Base64.decodeBase64(jwt.split("\.")[1])); aud = JSONObject.parseObject(claim).get("aud").toString(); sub = JSONObject.parseObject(claim).get("sub").toString(); } JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey); jwtParser.requireIssuer("https://appleid.apple.com"); jwtParser.requireAudience(aud); jwtParser.requireSubject(sub); try { Jws<Claims> claim = jwtParser.parseClaimsJws(jwt); if (claim != null && claim.getBody().containsKey("auth_time")) { System.out.println(claim); return true; } return false; } catch (ExpiredJwtException e) { return false; } catch (Exception e) { return false; } } /** * 对前端传来的JWT字符串identityToken的第二部分进行解码 * 主要获取其中的aud和sub,aud大概对应ios前端的包名,sub大概对应当前用户的授权的openID * @param identityToken * @return {"aud":"com.xkj.****","sub":"000***.8da764d3f9e34d2183e8da08a1057***.0***","c_hash":"UsKAuEoI-****","email_verified":"true","auth_time":1574673481,"iss":"https://appleid.apple.com","exp":1574674081,"iat":1574673481,"email":"****@qq.com"} */ public static JSONObject parserIdentityToken(String identityToken){ String[] arr = identityToken.split("\."); Base64 base64 = new Base64(); String decode = new String (base64.decodeBase64(arr[1])); String substring = decode.substring(0, decode.indexOf("}")+1); JSONObject jsonObject = JSON.parseObject(substring); return jsonObject; } }
2.编写业务逻辑代码
public AuthUser appleLogin(String identityToken){ String randomStr = UUID.randomUUID().toString(); try { //验证identityToken if(!AppleUtil.verify(identityToken)){ throw new RuntimeException("identityToken验证失败"); } //对identityToken解码 JSONObject json = AppleUtil.parserIdentityToken(identityToken); if(json == null){ throw new RuntimeException("identityToken解码失败"); } //苹果用户唯一标识 String appleId = new MD5().digestHex16(json.get("sub").toString()) ; SysUser user = baseMapper.selectOne(new MpUtil<SysUser>().queryNormal().eq(SysUser.APPLE_ID,appleId)); //判断该账户是否被禁用 if(user!=null && user.getDataActive().equals(StatusEnum.STATUS_DISABLE.getStrCode())){ throw new RuntimeException("该账户已被禁用,请联系管理员!"); } //授权绑定过直接获取token if(user!=null){ //非密码登录设置密码为空 user.setPassword(null); return getToken(user); //把苹果的登录唯一标识存储redis中 }else { RedisUtil.addDataSecond(StrUtil.format(APPLE_AUTH_LOGIN, randomStr),appleId,600l); AuthUser authUser = new AuthUser(); //把键存入这个字段 authUser.setAccessToken(randomStr); return authUser; } }catch (Exception e){ throw new RuntimeException("系统错误!请联系管理员"); } }