Apple 注销 Revoke tokens

至2022年6月30日之后,苹果app中有apple账号登录的,必须要有注销接口,也就是说必须得调用苹果的账号注销接口

为了让大家也能快速的调通,我决定将我的代码以及思路分析出来,首先我是做后端开发的 语言使用的是 JAVA

思路:

​ 首先要和ios开发那边沟通那些参数他传给后端,当然自己要先知道自己需要什么,这个很重要,先看这个文档参数

jpuuad.png

参数 解析:

​ 需要注意:content-type 的类型为 Content-Type: application/x-www-form-urlencoded

client_id:这个参数就是Bundle Identifier ,如果你和我一样是后端开发并不知道你就直接问ios开发他肯定知道

client_secret: 这个参数比较麻烦一点点,这个参数我是使用p8 文件 生成的密钥具体实现

token:这个参数需要ios端再让用户授权获取到code 传到后端,后端在使用这个code去请求 这个接口

​ https://appleid.apple.com/auth/token
​ 文档地址: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens

jpKQw4.png

这个接口我们传四个参数 分别是

client_id : Bundle Identifier 一样是填这个

`client_secret : 这个参数和上面说的一样,代码最后附上

code : 让ios开发者传给你,需要注意的是这个code 五分钟过期

grant_type :传authorization_code这个就完事了

最后拿到返回结果中的:access_token 就是我们要的token

{

  "access_token": "a08e84f841fd941524.0.rwvx.yplgeDRaP3F-v5Ek9-7QOA",

  "token_type": "Berer",

  "expires_in": 3600,

  "refresh_token": "r81edbac8b9bd482e1.0.rwvx.M9KauvbR09JrzKa8WZ83Lw",

  "id_token": "eyJraWQiOiJZdXlYb1kiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnl1Y2hlbmcuc21hcnRoZWFsdGgiLCJleHAiOjE2NTU4Njc2MzAsImlhdCI6MTY1NTc4MTIzMCwic3ViIjoiMDAwNjU3LmE2YjAxMjU0MWNiNDRjYjZiNmVjMjBkYjRkYWIwNDEwLjA3NDUiLCJhdF9oYXNoIjoiNVVBQXFKUmFvX0JodzJXdS13ak1odyIsImF1dGhfdGltZSI6MTY1NTc4MDk4NCwidHJhbnNmZXJfc3ViIjoiMDAwNjU3LnI5Y2E1NjZkYzQ0YjI0NTJkYTRmM2I5YjRiOTI4OTc0YiIsIm5vbmNlX3N1cHBvc"

}

最后一个参数

token_type_hint:填access_token

我写的代码:

  /**
     * 获取p8文件中的内容
     *
     * @param clientType
     * @return
     */
    private static Key getPrivateKey(String clientType) {
        try {
            File file = new File(p8FilePat + clientType + ".p8");
            BufferedReader br = new BufferedReader(new FileReader(file));
            String string = null;
            StringBuffer sb = new StringBuffer();
            while ((string = br.readLine()) != null) {
                if (string.startsWith("---")) {
                    continue;
                }
                sb.append(string);
            }
            br.close();

            KeyFactory factory = KeyFactory.getInstance("EC");
            EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(org.apache.commons.codec.binary.Base64.decodeBase64(sb.toString().replaceAll("\\n", "")));
            return factory.generatePrivate(keySpec);
        } catch (FileNotFoundException e) {
            log.error("not find p8 file !=>{}", e.getMessage());
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 私钥加密后给苹果去验证,构造clientSecret,就是构造一个jwt字符串
     * [获取私钥]
     *
     * @param iss team_id
     * @param sub client_id
     * @param kid access_token
     * @return
     */
    public static String buildJwt(String iss, String sub, String kid) {
        Map<String, Object> header = new HashMap<>();
        header.put("alg", SignatureAlgorithm.ES256.getValue()); //SHA256withECDSA
        header.put("kid", kid);

        long iat = System.currentTimeMillis() / 1000; //以秒为单位
        Map<String, Object> claims = new HashMap<>();
        claims.put("iss", iss);// apple开发组id 问ios开发要
        claims.put("iat", iat); 
        claims.put("exp", iat + 180 * 3600); //设置过期时间
        claims.put("aud", "https://appleid.apple.com"); //固定值
        claims.put("sub", sub);// Bundle Identifier 
        return new DefaultJwtBuilder().setHeader(header).setClaims(claims).signWith(SignatureAlgorithm.ES256, getPrivateKey(sub)).compact();
    }

    /**
     * 用户授权获取
     *
     * @param code
     * @param clientId
     * @return
     */
    public static String getAuthToken(String code, String clientId) {

        if (code.isEmpty() || clientId.isEmpty()) {
            return null;
        }
        String kid = "";
        // TODO 判断是那个app teamId 等到时候app迁移到另一个公司账号再做判断
        if ("com.***.***".equals(clientId)) {
            kid = Constants.APPLE_K_ID_SMARTHEALTH;
        } else if ("com.***.***".equals(clientId)) {
            kid = Constants.APPLE_K_ID_SMARTHEALTH_PRO;
        }
        if ("".equals(kid)) {
            log.error("apple getAuthToken 没有对应的app信息");
            return null;
        }

        JSONObject jsonObject = null;
        try {
            privateKeyStr = buildJwt(Constants.APPLE_TEAM_ID, clientId, kid);
            Map<String, String> stringStringHashMap = new HashMap<>();
            stringStringHashMap.put("client_id", clientId);
            stringStringHashMap.put("client_secret", privateKeyStr);
            stringStringHashMap.put("code", code);
            stringStringHashMap.put("grant_type", "authorization_code");
            String res = HttpRequest.post(Constants.APPLE_AUTH_TOKENS_URL).contentType("application/x-www-form-urlencoded").query(stringStringHashMap).send().body();
            jsonObject = JSON.parseObject(res);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return jsonObject.get("access_token").toString();
    }

    public static Boolean appleRevoke(String code, String clientId) {
        if (clientId.isEmpty()) {
            return false;
        }
        try {
            String authToken = getAuthToken(code, clientId);
            Map<String, String> requestMap = new HashMap<>();
            requestMap.put("client_id", clientId);
            requestMap.put("client_secret", privateKeyStr);
            requestMap.put("token", authToken);
            requestMap.put("token_type_hint", "access_token");
            System.out.println(requestMap);
            HttpResponse send = HttpRequest.post(Constants.APPLE_REVOKE_TOKENS_URL)
                    .contentType("application/x-www-form-urlencoded")
                    .query(requestMap)
                    .send();
            int statusCode = send.statusCode();
            if (statusCode != 200) {
                JSONObject jsonObject = JSON.parseObject(send.body());
                String error = jsonObject.get("error").toString();
                System.out.println("error --------- " + error);
                if (!error.isEmpty()) {
                    return false;
                }
            }
        } catch (Exception e) {
            log.error("revoke token error");
            return false;
        }
        return true;
    }

我这个调试代码,为了兼容多个app所以有些参数改成了动态的

写这篇文章呢

1、是为了记录一下

2、是方便大家,给大家点思路

3、我不是经常写所以并不是写的很好理解一下啊

有什么不懂的留言 谢谢支持!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值