一、apple配置

1、注册开发者

在apple开发者官网( https://developer.apple.com/)注册成开发者

2、创建应用

  1. 点击左边菜单的Certificates, Identifiers & Profiles
  2. 点击左边的菜单的Identifiers 创建应用(记得开通苹果登录)
  3. 记下创建应用的包名(apple clientId)

3、获取apple teamId

  1. 右上角的账号名后面的编号即apple TeamId

4、获取密钥id和jwt密钥

  1. 在2步骤中的页面点击 keys
  2. 创建新的密钥
  3. 注册密钥成功后即可获得apple kid 和apple jwt key(只能下载一次,文件为.p8格式)

5、记录apple clientId、teamId、kid、jwtKey 后续开发需要使用到

二、apple授权登录时序图

三、apple授权登录相关官方文档

1、官方文档地址

https://developer.apple.com/documentation/sign_in_with_apple

2、获取公钥地址

  1. 获取公钥地址的文档地址https://developer.apple.com/documentation/sign_in_with_apple/fetch_apple_s_public_key_for_verifying_token_signature
  2. 接口地址
    https://appleid.apple.com/auth/keys
  3. 注意事项
    接口返回的密钥值是固定的,可以适当缓存使用

3、校验token地址

  1. 校验token的文档地址https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
  2. 接口地址
    https://appleid.apple.com/auth/token

四、注意事项

apple登录只有在第一次授权的时候可以获取到用户信息

五、参考代码

  1. 获取apple公钥列表
String GET_PUBLIC_KEY = "https://appleid.apple.com/auth/keys";
ResponseEntity<String> getApplePublicKeyResp = restTemplate.getForEntity(GET_PUBLIC_KEY, String.class);String body = getApplePublicKeyResp.getBody();JSONObject resultNode =JSONObject.parseObject(body);JSONArray keys = resultNode.getJSONArray("keys");Map<String, String> applePublicKeyMap = new HashMap<>(4);for (int i=0;i<keys.size();i++) {JSONObject jsonObject = keys.getJSONObject(i);String kid = jsonObject.getString("kid");applePublicKeyMap.put(kid , jsonObject.toString);}
  1. 生成客户端密钥
/*** 生成客户端密钥,这个密钥有效期为半年** @return 密钥*/@SneakyThrowsprivate String getClientSecret() {String kid="apple kid";String teamId ="apple teamId";String clientId= "apple clientId";String clientSecret = Jwts.builder().setHeaderParam(JwsHeader.ALGORITHM, "ES256").setHeaderParam(JwsHeader.KEY_ID, kid).setIssuer(teamId).setAudience("https://appleid.apple.com").setSubject(clientId).setExpiration(new Date(System.currentTimeMillis()+180*24*60*60*1000L)).setIssuedAt(new Date(System.currentTimeMillis())).signWith(SignatureAlgorithm.ES256, getJwtEncryptKey()).compact();return clientSecret;}```java/*** 生成jwt密钥** @return jwt密钥*/@SneakyThrowsprivate PrivateKey getJwtEncryptKey() {String jwtEncryptKey ="apple jwtKey";PEMParser pemParser = new PEMParser(new StringReader(jwtEncryptKey));JcaPEMKeyConverter converter = new JcaPEMKeyConverter();PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();return converter.getPrivateKey(object);}
  1. 校验token
        String CHECK_TOKEN_URL = "https://appleid.apple.com/auth/token";HttpHeaders reqHeaders = new HttpHeaders();MediaType type = MediaType.parseMediaType("application/x-www-form-urlencoded");reqHeaders.setContentType(type);MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<>(5);requestMap.add("client_id", clientId);requestMap.add("client_secret", getClientSecret());requestMap.add("code", token);requestMap.add("grant_type", "authorization_code");requestMap.add("redirect_uri", null);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(requestMap, reqHeaders);ResponseEntity<String> checkResponseEntity = restTemplate.postForEntity(CHECK_TOKEN_URL, request, String.class); String body = checkResponseEntity.getBody();JSONObject resultNode =JSONObject.parseObject(body);Optional<String> idToken = Optional.ofNullable(resultNode ).map(it -> it.getString("id_token"));Claims claims =getClaims(idToken.get());String sub = claims.getSubject();if (!unionId.equals(sub)) {log.error("用户传递的唯一标识非法,unionId is {},request userId is {}", unionId, sub);}
  1. 解析校验token中的值
 private Claims  getClaims (String idToken){String jwtHeaderEncoded = idToken.split("\\.")[0];String jwtHeader = new String(Base64.decodeBase64(jwtHeaderEncoded));JSONObject jwtHeaderNode =JSONObject.parseObject(jwtHeader);ApplePublicKey applePublicKey = applePublicKeyMap(jwtHeaderNode.getString("kid"));PublicKey publicKey = generatePublicKey(applePublicKey.getN(), applePublicKey.getE());return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(idToken).getBody();}private PublicKey generatePublicKey(String n, String e) {BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));KeyFactory keyFactory = KeyFactory.getInstance("RSA");RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);return keyFactory.generatePublic(spec);}

apple授权登录(服务端)相关推荐

  1. 联系微信ID服务器失败,微信小程序-新用户获取微信手机号登录服务端获取不到unionid情况...

    需求:微信小程序进行获取手机号登录时,登录失败 授权微信用户信息 授权微信手机号 bindLogin: function(e) { wx.hideLoading(); console.log(e.de ...

  2. 云信服务器代码,云信一键登录服务端API文档-一键登录-网易云信开发文档

    一键登录 > 服务端 API 文档 一键登陆服务端API文档 接口概述 API调用说明 本文档中,所有调用网易云信服务端接口的请求都需要按此规则校验. API checksum校验 以下参数需要 ...

  3. Apple 授权登录

    如果使用了第三方登录(例如 Google auth), 那么 app store 就要求一定要使用 apple 授权登录, 否则上架会被拒绝 Guideline 4.8 - Design - Sign ...

  4. apple登录服务端验证

    Sign In With Apple 从登陆到服务器验证 服务端向苹果请求验证 手机端需要提交 user .authorizationCode . identityToken 字段信息(code和to ...

  5. sign in with Apple,使用Apple授权登录

    软件环境:Xcode 11.4.iOS13+ 创建时间:2020年 03月15号 更新时间:2021年 03月02号 这篇文章都说了什么 使用Apple登录的注意事项 接入原理概览 客户端编码 审核规 ...

  6. facebook登录服务端校验,Facebook oidc,Meta oidc服务端校验

    相对应的客户端文档可以先阅读这里: https://developers.facebook.com/docs/facebook-login/limited-login/ios 如果你选择的是 http ...

  7. SSO单点登录教程(四)自己动手写SSO单点登录服务端和客户端

    作者:蓝雄威,叩丁狼教育高级讲师.原创文章,转载请注明出处. 一.前言 我们自己动手写单点登录的服务端目的是为了加深对单点登录的理解.如果你们公司想实现单点登录/单点注销功能,推荐使用开源的单点登录框 ...

  8. 一键登录服务端原理_一键登录已成大势所趋,Android端操作指南来啦!

    根据极光(Aurora Mobile)发布的<2019年Q2移动互联网行业数据研究报告>,2019年第二季度,移动网民人均安装APP总量已达56款.面对如此繁多的APP,想在用户的手机中占 ...

  9. [精华][推荐]CAS SSO单点登录服务端客户端学习

    1.了解单点登录 SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用(多 ...

最新文章

  1. 美国字节程序员吐槽:国内同事太卷了!工资买不起房,卷的意义是什么?
  2. java多线程总结图_Java多线程总结之Queue
  3. php mysql pdo use_PHP连接到mysql的方法--mysqli和PDO
  4. windows下实现Git在局域网使用
  5. 【Groovy】Groovy 扩展方法 ( Groovy 扩展方法引入 | 分析 Groovy 中 Thread 类的 start 扩展方法 )
  6. JavaScript实现depth First Search深度优先搜索算法(附完整源码)
  7. spingboot和mybatis,纯注解方式
  8. makefile编译问题记录
  9. 麻省理工学院给研究生的文献阅读方法,简单高效!
  10. 高速建成Android开发环境ADT-Bundle和Hello World
  11. jupyter notebook 某个cell 一直在运行
  12. STM32 使用片外外扩内存调试
  13. Java基础学习总结(134)——JDK 11 是否值得更新的思考
  14. php怎么打印json数据,php输出json格式数据的例子
  15. linux 0.11 内核学习 -- bootsect.s, 万里长征第一步
  16. 强化学习总结(1)--EE问题
  17. html预览页面做成a4纸,如何在A4纸张尺寸页面制作HTML页面?
  18. 【Mybatis入门20221024】
  19. 经常调试笔记本服务器显示器,瞎折腾!闲置损坏笔记本电脑改造的DIY液晶显示屏!蜗牛星际附件。...
  20. Java实现aes加解密

热门文章

  1. Vue 中使用高德地图api
  2. 基于SVG的绘制多边形jQuery插件
  3. Python3 获取法定节假日
  4. 【Python教程】十三、我连对象都找不到还让我用对象?类与对象(一)
  5. 如何用vba做答题、抽点类ppt
  6. 百度搜索结果页面的参数_反馈搜索结果用时(rsv_sug4)
  7. linux定时压缩脚本,使用shell脚本对日志文件进行定时压缩
  8. python基础之温度转换
  9. accept搭配用法_accept for的用法与搭配
  10. 2019届高三理科数学选择填空整理