码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • PHP 接入 Apple 登录对 identityToken 验证


    需用到 Composer 库:firebase/php-jwt,直接安装即可 composer require firebase/php-jwt

    资源

    生成 Apple 登录按钮图标:https://appleid.apple.com/signinwithapple/button

    官方文档(使用 Apple 登录):https://developer.apple.com/documentation/sign_in_with_apple

    生成并验证 Token:https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens

    校验 Identity Token:https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/verifying_a_user#3383769

    这个简单说下,苹果建议使用 5 个校验

    1. 使用公钥校验 JWS E256 签名
    2. 验证 nonce 随机数
    3. 验证 iss 字段包含 https://appleid.apple.com
    4. 验证 aud 字段为开发者的 client_id(即 Bundle ID)
    5. 验证当前时间早于 exp 字段时间

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

    获取 access_token/identityToken

    简单示例下 UniApp 中通过 uni.login() 方法获取 JWT

    let type = 'apple'
    
    uni.getProvider({
        service: 'oauth',
        success: (res) => {
            if (res.provider.includes(type)) {
                uni.login({
                    provider: type,
                    success: (authed) => {
                        console.log('三方登录获取用户信息成功', authed)
    
                        // Apple 登录这儿可用 authed.authResult 或 authed.appleInfo 得到授权数据
                        // authResult.access_token 与 appleInfo.identityToken 相同;authResult.openid 与 appleInfo.user 相同
                        // 但 Authorization Code 存在于 appleInfo,即 appleInfo.authorizationCode
                        // TODO: 登录请求
                    },
                    fail: (err) => {
                        console.log('三方登录获取登录信息失败', err)
    
                        if (err.errCode === 1001) {
                            // 登录已取消
                        } else {
                            // 其它错误情况
                        }
                    }
                })
            } else {
                // 当前环境不支持该登录方式
            }
        },
        fail: (err) => {
            console.log('获取三方登录信息异常', err)
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    获取 Apple 公钥

    公钥说明:https://developer.apple.com/documentation/sign_in_with_apple/fetch_apple_s_public_key_for_verifying_token_signature

    需要注意的是这段说明:

    The endpoint can return multiple keys, and the count of keys can vary over time. From this set of keys, select the key with the matching key identifier (kid) to verify the signature of any JSON Web Token (JWT) issued by Apple. For more information, see the JSON Web Signature specification.
    该接口会返回多个密钥,并且密钥的数量会随着时间发生变化。在该密钥集中,选择具有标识符(kid)的密钥来验证所有由 Apple 颁布的 JWT 签名。有关更多信息,请参阅 JSON Web 签名规范。

    公钥接口:https://appleid.apple.com/auth/keys

    因为该密钥集会产生变化,所以在不了解更新周期的情况下 不建议缓存 该内容

    获取后需进行解码 $keys = json_decode($keys, true);

    解析 $keys(公钥)

    这里就需要使用安装的 Composer 库了:

    try {
        $parsedKeys = \Firebase\JWT\JWK::parseKeySet($keys);
    } catch (Exception $e) {
        // 一定要捕获异常并自行处理解析 Key 失败的情况
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    解码获取 OpenID

    一定要捕获异常,decode 方法会抛出 7 种不同的异常,有个简单且友好的做法是单独判断过期异常并响应友好提示

    try {
        $decoded = \Firebase\JWT\JWT::decode($token, $parsedKeys);
    } catch (\Exception $e) {
        if ($e instanceof \Firebase\JWT\ExpiredException) {
            // 返回友好提示告知用户授权过期
        }
    
        // 可直接响应登录异常或参数异常
    }
    
    // JWT 中 sub 即为 OpenID
    $openId = $decoded->sub;
    // 邮箱地址
    $email = $decoded->email;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    多说两句

    1. Apple 登录授权后前端除了拿到 identityToken 还有一个 user 也是 OpenID,但是该 OpenID 不可信,可以在解码 JWT 后进行对比;
    2. JWT 的有效期是 10 分钟;

    解码后的完整结果(var_dump 示例):

    class stdClass#89 (10) {
      public $iss =>
      string(25) "https://appleid.apple.com"
      public $aud =>
      string(15) "Bundle ID"
      public $exp =>
      int(1695473542)
      public $iat =>
      int(1695387142)
      public $sub =>
      string(44) "此段为 OpenID"
      public $c_hash =>
      string(22) "一段 hash 值"
      public $email =>
      string(18) "Apple ID 邮箱地址"
      public $email_verified =>
      string(4) "true"
      public $auth_time =>
      int(1695387142)
      public $nonce_supported =>
      bool(true)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    手把手带你学python—牛客网python基础 生成字典
    动态顺序表的增删查改(C语言实现)
    【好书推荐】程序是怎样跑起来的
    新手QML贪吃蛇 Qt Quick
    ASP.NET MVC多表示例题-酒店管理
    C++17 std::filesystem 用法指北
    【题解】蒙德里安的梦想
    前端使用Threejs控制机械臂模型运动(我在CSDN的第一篇文章)
    微信小程序结合php后台实现登录授权机制详解
    谷粒学苑_第十天
  • 原文地址:https://blog.csdn.net/maxsky/article/details/126904637
  • 最新文章
  • 【FHE】我们如何实现同态加密推理(八):SiLU 的密文化——两条路径,和一个 8 字节的开关
    SQLcl 中 c/old/new 替换变量为何失效?先定位再替换
    不让模型写作文,直接从它脑子里读答案:Jev 决策在 .NET 的两条路线
    Halo插件:支持GitHub的图床附件策略
    电视投屏界的“一股清流”!SimpleTVCast 6.0.0-beta 抢先体验:无需TV端App,界面大换血!✨
    华三VXLAN集中式网关实战指南:Spine多活网关 + 双活接入(M-LAG)
    软件更好写之后口碑会更重要
    大 O、大 Omega、大 Theta 的区别,O(n) 复杂度是什么意思
    Java标签跳转:一个鲜为人知但却很实用的小技巧
    多智能体系统论文速读
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
小工具 小游戏
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

京公网安备 11010502049817号