Skip to content

Instantly share code, notes, and snippets.

@mitoop
Last active April 25, 2021 05:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mitoop/6c86477873778c87fd79959f1cf72793 to your computer and use it in GitHub Desktop.
Save mitoop/6c86477873778c87fd79959f1cf72793 to your computer and use it in GitHub Desktop.
Laravel Apple Sign In Laravel 苹果登录

1. 前述

在 WWDC2019 中,苹果官方约定如果新的APP(目前为止未在AppStore发布过的), 如果有第三方登录功能(QQ登录,谷歌登录等等), 那么必须适配苹果推出的Sign In With Apple才能被审核通过。

2. 苹果开发者中进行配置

2.1 具体配置 参考 :https://mp.weixin.qq.com/s/xkxCnKqA0u-guEYcYCkcOg 或者谷歌

2.2 后端需要的参数 client_id / client_secret

client_id 为 配置中的 Bundle ID 通常为 com.xxx.xxx

client_secret 后端需要根据 client_id / team_id / key_id / p8文件 这几个参数 生成

2.3 生成 client_secret

生成 client_secret 需要使用下面这个 ruby 脚本 创建 secret_gen.rb 文件并将下面代码复制进去

require "jwt"

key_file = "P8文件本地路径"
team_id = "Your Team ID"
client_id = "Your App Bundle ID"
key_id = "The Key ID of the private key"
validity_period = 180 # In days. Max 180 (6 months) according to Apple docs.

private_key = OpenSSL::PKey::EC.new IO.read key_file

token = JWT.encode(
  {
    iss: team_id,
    iat: Time.now.to_i,
    exp: Time.now.to_i + 86400 * validity_period,
    aud: "https://appleid.apple.com",
    sub: client_id
  },
  private_key,
  "ES256",
  header_fields=
  {
    kid: key_id 
  }
)
puts token

修改这四个参数

key_file = "P8文件本地路径"
team_id = "Your Team ID"
client_id = "Your App Bundle ID"
key_id = "The Key ID of the private key"

运行 ruby secret_gen.rb 就可以生成 client_secret 了(本地需要有 ruby 环境)

3. Laravel端

3.1 需要引入社会化登录组建并引入Apple登录插件

composer require laravel/socialite
composer require socialiteproviders/apple
3.2.1 配置核心参数

config/services.php文件中 中增加配置项

'apple' => [    
  'client_id' => env('APPLE_CLIENT_ID'), // client id 
  'client_secret' => env('APPLE_CLIENT_SECRET'),  // 生成好的 client_secret
  'redirect' => env('APPLE_REDIRECT_URI') // APP端不需要这个 为空或者随便写入一个地址 如: `https://example-app.com/redirect`
]
3.2.2 配置事件监听

app/Providers/EventServiceProvider 文件中的 listen[] 数组中增加

protected $listen = [
    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        // ... other providers
        'SocialiteProviders\\Apple\\AppleExtendSocialite@handle',
    ],
];

3.3 业务代码demo

3.3.1 数据库设置

需要在用户表增加 apple openid 字段 apple openid 字段格式为 000472.39a0b935d1f14d2bae90c8d68abd1c3b.0450

可以增加一个 apple openid_hash字段 用来建立索引查询 hash字段的值为 md5(openid)

如果没有用 openid_hash 字段给 openid 字段增加唯一索引

如果使用 openid_hash 字段给 openid_hash 字段增加唯一索引 openid字段不需要索引了

3.3.2

假设在 业务代码在 LoginControllerloginByApple方法中

3.3.2.1 请求参数

code : [必须的参数] code参数即是APP端获取的 authorizationCode 参数,authorizationCode 原始格式为二进制需要转为普通的字符串传递给后端

用户信息参数: 用户第一次登录的时候APP端可以获取到 用户的邮箱 和 用户名 (邮箱如果用户不给权限 Apple会给一个中转邮箱)

可以根据业务是否需要这两个字段 只有第一次登录会有这两个参数 所以这两个参数不是必须的

其它参数: 根据业务自行设计

3.3.2.2 伪代码
public function loginByApple()
{
   try{
     /* @var \SocialiteProviders\Manager\OAuth2\User $user*/
     if ($oauthUser = \Laravel\Socialite\Facades\Socialite::with('apple')->stateless()->user()) {
        // 0. 进入这里 说明登录成功 继续获取 openid, openid 是用户的唯一标示
        // 1. 获取open id
        $openId = $oauthUser->getId();
        // 2. 根据open id (或者 open id hash)查找用户是否存在
        // 3. 存在的处理
        // 4. 不存在创建用户处理
        // 5. 其它更多具体业务的处理
     }
   }catch(\Throwable $t){
      // 这里错误有常见两种
      // 1. Client error: POST https://appleid.apple.com/auth/token resulted in a 400 Bad Request response:\n{\"error\":\"invalid_client\"}\n
      // 提示 invalid_client 的错误 说明配置 client_id 或者 client_secret 错误 通常是 client_secret 错误 请检查配置项和生成脚本
      // 2. 提示 grant 错误 很可能因为客户端提交的 code 参数被使用了
   }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment