Sign in With Apple (苹果授权登录)

关于Sign in With Apple (苹果授权登录)的问题,公司app上架appStore被拒原因是使用第三方授权登陆但是却没有使用苹果账号的授权登陆,苹果强制要求涉及到第三方登陆的app要集成apple账号登录,成功后特此记录一下。
一、第一步要引入的jar包

<!-- ↓↓↓↓↓↓↓↓ Sign in With Apple (苹果APP授权登录)相关↓↓↓↓↓↓↓↓ zh-->
<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>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</version>
</dependency>
<!-- ↑↑↑↑↑↑↑↑ Sign in With Apple (苹果APP授权登录)相关 ↑↑↑↑↑↑↑↑ zh-->

二、第二步加上网络请求工具类 HttpClientUtils

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;/*** HttpClient工具类* @author zhanghao*/
public class HttpClientUtils
{private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); // 日志记录private static RequestConfig requestConfig = null;static{// 设置请求和传输超时时间requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();}/*** post请求传输json参数* @param url  url地址* @param json 参数* @return*/public static JSONObject httpPost(String url, JSONObject jsonParam){// post请求返回结果CloseableHttpClient httpClient = HttpClients.createDefault();JSONObject jsonResult = null;HttpPost httpPost = new HttpPost(url);// 设置请求和传输超时时间httpPost.setConfig(requestConfig);try{if (null != jsonParam){// 解决中文乱码问题StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");entity.setContentEncoding("UTF-8");entity.setContentType("application/json");httpPost.setEntity(entity);}CloseableHttpResponse result = httpClient.execute(httpPost);// 请求发送成功,并得到响应if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK){String str = "";try{// 读取服务器返回过来的json字符串数据str = EntityUtils.toString(result.getEntity(), "utf-8");// 把json字符串转换成json对象jsonResult = JSONObject.parseObject(str);}catch (Exception e){logger.error("post请求提交失败:" + url, e);}}}catch (IOException e){logger.error("post请求提交失败:" + url, e);}finally{httpPost.releaseConnection();}return jsonResult;}/*** post请求传输String参数 例如:name=Jack&sex=1&type=2* Content-type:application/x-www-form-urlencoded* @param url            url地址* @param strParam       参数* @return*/public static JSONObject httpPost(String url, String strParam){// post请求返回结果CloseableHttpClient httpClient = HttpClients.createDefault();JSONObject jsonResult = null;HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);try{if (null != strParam){// 解决中文乱码问题StringEntity entity = new StringEntity(strParam, "utf-8");entity.setContentEncoding("UTF-8");entity.setContentType("application/x-www-form-urlencoded");httpPost.setEntity(entity);}CloseableHttpResponse result = httpClient.execute(httpPost);// 请求发送成功,并得到响应if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK){String str = "";try{// 读取服务器返回过来的json字符串数据str = EntityUtils.toString(result.getEntity(), "utf-8");// 把json字符串转换成json对象jsonResult = JSONObject.parseObject(str);}catch (Exception e){logger.error("post请求提交失败:" + url, e);}}}catch (IOException e){logger.error("post请求提交失败:" + url, e);}finally{httpPost.releaseConnection();}return jsonResult;}/*** 发送get请求* @param url 路径* @return*/public static JSONObject httpGet(String url){// get请求返回结果JSONObject jsonResult = null;CloseableHttpClient client = HttpClients.createDefault();// 发送get请求HttpGet request = new HttpGet(url);request.setConfig(requestConfig);try{CloseableHttpResponse response = client.execute(request);// 请求发送成功,并得到响应if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){// 读取服务器返回过来的json字符串数据HttpEntity entity = response.getEntity();String strResult = EntityUtils.toString(entity, "utf-8");// 把json字符串转换成json对象jsonResult = JSONObject.parseObject(strResult);}else{logger.error("get请求提交失败:" + url);}}catch (IOException e){logger.error("get请求提交失败:" + url, e);}finally{request.releaseConnection();}return jsonResult;}}

三、第三步加上与苹果服务器交互和验证SignInWithApple

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;import java.security.PublicKey;import org.apache.commons.codec.binary.Base64;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwk.Jwk;/*** * @author zhanghao**/
public class SignInWithApple {/*** 解密信息** @param identityToken APP获取的identityToken* @return 解密参数:失败返回null*/public static String verify(String identityToken) {try {if (identityToken.split("\\.").length > 1) {String claim = new String(Base64.decodeBase64(identityToken.split("\\.")[1]));String aud = JSONObject.parseObject(claim).get("aud").toString();String sub = JSONObject.parseObject(claim).get("sub").toString();String reuslt  ="FAIL";//此处循环遍历的原因是因为只取第一个会出现非法token的异常for (int i = 0; i < getPublicKey().size(); i++) {JSONObject jsonObject1 = JSONObject.parseObject(getPublicKey().getString(i));Jwk jwa = Jwk.fromValues(jsonObject1);PublicKey publicKey = jwa.getPublicKey();reuslt = verify(publicKey, identityToken, aud, sub);if(reuslt.equals("SUCCESS")){break;}}if (reuslt.equals("SUCCESS")) {System.out.println(reuslt);return claim;}else{System.out.println(reuslt);return "FAIL";}}} catch (Exception e) {e.printStackTrace();}return null;}/*** 此处验证* @param key* @param jwt* @param audience* @param subject* @return* @throws Exception*/public static String verify(PublicKey key, String jwt, String audience, String subject) throws Exception {String result = "FAIL";JwtParser jwtParser = Jwts.parser().setSigningKey(key);jwtParser.requireIssuer("https://appleid.apple.com");jwtParser.requireAudience(audience);jwtParser.requireSubject(subject);try {Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);if (claim != null && claim.getBody().containsKey("auth_time")) {result = "SUCCESS";return result;}} catch (ExpiredJwtException e) {result = "苹果token过期";return result;} catch (SignatureException e) {result = "苹果token非法";return result;}return result;}/*** 生成公钥串** @return 构造好的公钥串*/public static JSONArray getPublicKey() {try {String str = HttpClientUtils.httpGet("https://appleid.apple.com/auth/keys").toString();JSONObject data = JSONObject.parseObject(str);String keys = data.getString("keys");JSONArray arr = JSONObject.parseArray(keys);return arr;} catch (final Exception e) {e.printStackTrace();}return null;}
}

四、第四步处理自己的业务逻辑
暴露给移动端的接口
参数:
String identityToken, 拉取信息
String authorizationCode, 苹果说要传的但是没用到
String fullName, 用户名
String email, 邮箱
String appleId 唯一id 也就是UserId 用于与自己业务系统账号绑定

// 请求接口获取返回值String is = SignInWithApple.verify(identityToken);//验证成功后if (is!="FAIL") {// 请求成功// 根据appleId查詢系统中是否有該用戶此处省略查询用户的方法if(false){//如果没有该用户调用创建用户方法此处省略创建用户的方法}else{//如果有该用户更新token此处省略更新token的方法}}else {//验证失败}

Sign in With Apple (苹果授权登录)相关推荐

  1. Apple Sign in with Apple(苹果授权登录PHP)

    Apple Sign in with Apple(苹果授权登录PHP) 文章目录 Apple Sign in with Apple(苹果授权登录PHP) 一.登录Apple Developer 二.创 ...

  2. 苹果授权登录Sign In With Apple亲测通过版[100%成功]

    苹果授权登录Sign In With Apple后台代码实现JAVA版本亲测通过版 废话不多说,直接复制把自己的包名写上就可以用了 有个别的小坑,HttpUtil自己写,没附上 Base64一定要用o ...

  3. iOS 苹果授权登录(Sign in with Apple)

    在 iOS13 中,如果 App 提供第三方登录,就必须添加 苹果登录 Sign in with Apple 选项,并要求所有开发者于 2020年4月之前 完成现有应用的更新,否则审核不给通过. iO ...

  4. iOS 苹果授权登录(Sign in with Apple)系列之Apple Developer配置篇

    原文 在 iOS13 中,如果 App 提供第三方登录,就必须添加 苹果登录 Sign in with Apple 选项,并要求所有开发者于 2020年4月之前 完成现有应用的更新,否则审核不给通过. ...

  5. php Sign in with Apple(苹果授权登录PHP后端接口)

    详细配置参考:https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple 本文主要参考: https: ...

  6. 苹果apple账号授权登录第三方APP

    Apple官方文档 前言:由于公司最近有个业务需求是要进行Apple账号授权登录,于是我看边看文档边借鉴其他人的写法,发现好多文章都有一个共性,一个是在解析JWT的时候自己设置参数后进行判断,这样做没 ...

  7. 【JAVA】对接苹果授权登录流程

    背景 苹果公司要求所有使用第三方登录的 App,都必须接入Sign in with Apple. 接入方式 基于JWT identityToken的算法验证 基于授权码的验证 校验流程 上图为苹果对接 ...

  8. 苹果授权登录 jwt node 解码

    苹果授权登录 jwt node 解码 const jwt_decode = require('jwt-decode') const NodeRSA = require('node-rsa'); con ...

  9. 【JAVA】接入苹果授权登录

    一.背景 公司上架APP到Apple Store,审核被打回,原因是APP中接入了其他第三方登录,所以必须要求接入苹果登录,这项新规定,逼不得已只要接入苹果登录. 二.使用JWT方式接入登录 参考网上 ...

最新文章

  1. SpringBoot整合JDBC、整合Druid数据源详解教程
  2. Android组件化打造知乎日报系列(一)—— 项目架构搭建
  3. Verilog设计实现俄罗斯方块游戏
  4. python3(七)os模块
  5. 一文读懂机器学习库graphLab
  6. 张小龙:做 PC 版微信是一种破坏,本来不想做
  7. Python文本词频统计
  8. oracle join(比较全面的解释了join)
  9. 史上最全科研网站!!!
  10. 机器学习_周志华_西瓜书_学习笔记_第16章--强化学习
  11. 马克笔字体软件测试,广东文艺职业学院2017年公开招聘专业技能测试试题
  12. java uuid to long,生成long类型的UUID
  13. 小程序即时配送配置指南
  14. 素问—渗透测试的简介
  15. JAVA基础之单例模式
  16. virt-install命令参数
  17. 绘画入门经典教程——如果你想, 一切皆有可能!
  18. brpc源码分析——线程模型
  19. 网络安全——技术与实践(第3版)课后题答案
  20. 求推荐微信可开发手持蓝牙打印设备

热门文章

  1. 使用git命令打补丁
  2. STM32串口DMA方式接收数据。类似环形FIFO。超省CPU资源!
  3. Selenium+iframe准确定位元素
  4. 教师python培训心得体会
  5. 【JZOJ】WZK打雪仗
  6. Excel用户打死想不到:表格能做APP,WPS用户:金山系出品就是牛
  7. Matlab动画模拟分子布朗运动的示例
  8. 直播带货这么火,如何在小程序中实现视频通话及直播互动功能?
  9. python---导入 py文件
  10. 10.5日饿了么复活了,大家凑合用用吧~(偶尔更新~)