IOS APPID一键登录服务端验证
程序员文章站
2022-03-03 10:14:47
...
public class IosAppIdLoginServiceImp { private static final Logger LOGGER = LoggerFactory.getLogger(IosAppIdLoginServiceImpl.class); @Autowired private PropertiesResouseUtil propertiesResouseUtil; private static final String AUTH_TIME = "auth_time"; private final static int READ_TIMEOUT = 100; private final static int CONNECT_TIMEOUT = 60; @Override public Response<T> verifyIdentityToken(Request<IosAppIdLoginDto> request) { Response<T> response = new Response<>(); IosAppIdLoginDto iosAppIdLoginDto = request.getRequestParam(); response.setResult(iosAppIdLoginDto); try { //解析 Map<String, JSONObject> json = parserIdentityToken(iosAppIdLoginDto.getIdentityToken()); JSONObject header = json.get("header"); String kid = header.getString("kid"); //生成publickey PublicKey publicKey = getPublicKey(kid); if (publicKey == null) { iosAppIdLoginDto.setSuccess(false); LOGGER.info("获取苹果验证公钥失败:kid={}",kid); return commonResponse; } JSONObject payload = json.get("payload"); //验证 JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey); jwtParser.requireIssuer(propertiesResouseUtil.getProperty("apple.url"));//+"/auth/keys" jwtParser.requireAudience(payload.getString("aud")); jwtParser.requireSubject(payload.getString("sub")); Jws<Claims> claim = jwtParser.parseClaimsJws(iosAppIdLoginDto.getIdentityToken()); if (claim != null && claim.getBody().containsKey(AUTH_TIME)) { // String sub = claim.getBody().get("sub").toString();//用户的Apple的openId // String iss = claim.getBody().get("iss").toString(); // String aud = claim.getBody().get("aud").toString(); iosAppIdLoginDto.setSuccess(true); } } catch (ExpiredJwtException e1) { iosAppIdLoginDto.setSuccess(false); LOGGER.error("apple token verify fail,identityToken is expired!",e1); } catch (Exception e2) { iosAppIdLoginDto.setSuccess(false); LOGGER.error("apple token verify fail,error={}", e2); } return commonResponse; } /** * 对前端传来的JWT字符串identityToken的第二部分进行解码 * 主要获取其中的aud和sub,aud对应ios前端的包名,sub对应当前用户的授权openID * * @param identityToken * @return */ private Map<String, JSONObject> parserIdentityToken(String identityToken) { Map<String, JSONObject> map = new HashMap<String, JSONObject>(); String[] arr = identityToken.split("\\."); String deHeader = new String(Base64.decodeBase64(arr[0])); JSONObject header = JSON.parseObject(deHeader); LOGGER.info("获取的header={}",header); map.put("header", header); String dePayload = new String(Base64.decodeBase64(arr[1])); LOGGER.info("获取dePayload={}",header); JSONObject payload = JSON.parseObject(dePayload); map.put("payload", payload); return map; } /** * 获取publickey * @param kid * @return */ private PublicKey getPublicKey(String kid) { LOGGER.info("get apple public key start,kid={}", kid); try { Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(propertiesResouseUtil.getProperty("httpproxy.url"), Integer.parseInt(propertiesResouseUtil.getProperty("httpproxy.port")))); OkHttpClient client = new OkHttpClient().newBuilder().proxy(proxy).connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS).readTimeout(READ_TIMEOUT, TimeUnit.SECONDS).build(); Request request = new Request.Builder().url(propertiesResouseUtil.getProperty("apple.url")+"/auth/keys").build(); Response response = client.newCall(request).execute(); if(response.isSuccessful()){ // 得到响应体中的身体,将其转成 string String string = response.body().string(); JSONObject data = JSONObject.parseObject(string); JSONArray jsonArray = data.getJSONArray("keys"); if(jsonArray.isEmpty()) { return null; } for (Object object : jsonArray) { JSONObject json = ((JSONObject)object); if(json.getString("kid").equals(kid)) { json = ((JSONObject)object); Jwk jwa = Jwk.fromValues(json); return jwa.getPublicKey(); } } } } catch (final Exception e) { LOGGER.error("apple getPublicKey error", e); } return null; } } pom.xml 引用包
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>jwks-rsa</artifactId> <version>0.9.0</version> </dependency>