验证苹果登录, 官方提供两种验证方法, 一种是 token, 另一个种是 code. 这里使用的是 token
登录流程:
苹果客户端调用苹果 API, 获取到用户的信息, 包括:
user_id
昵称
identity_token
苹果客户端发送 identity_token 到服务端
服务端验证 identity_token 是否合法, 并解析数据, 得到 user_id. 这个 user_id 和上面的 user_id 是一样的
服务端检查该 user_id 是否已注册, 如果是, 返回登录信息. 如果否, 注册.
验证的原理:
苹果会把用户的信息放在一个 JSON 里面, 然后使用私钥对 JSON 签名.
服务端调用苹果 API 拿到公钥, 然后验证签名是否正确.
所以总的来说就是使用 RSA 私钥签名的算法来保证数据不会被篡改.
identity_token 解析后包含几部分内容
header.
例子:
{u'alg': u'RS256', u'kid': u'86D88Kf'}
alg 是加密算法类型
kid 是使用的公钥的 id
payload 或者 claims . 也就是数据:
例子:
- {
- u'c_hash': u'HpjAKvLjivbJr9j9ZxfFxA',
- u'aud': u'com.kugou.moe',
- u'iss': u'https://appleid.apple.com',
- u'email_verified': u'true',
- u'nonce_supported': True,
- u'exp': 1583829815,
- u'auth_time': 1583829215,
- u'iat': 1583829215,
- u'email': u'huanghuixia5@163.com',
- u'sub': u'001712.90358ddaa2294989b3b7c88b30086b37.0724' # 用户唯一标志, 相当于 openid
- }
aud 客户端的报名.
exp. 超时时间, 时间戳. 当前时间如果大于这个时间, 会报超时错误
email 用户的 email
sub 用户的 user_id
demo
使用了 python-jwt 这个库. 安装方法: pip install python-jwt
- # encoding=utf8
- import requests
- import logging
- import python_jwt as jwt, jwcrypto.jwk as jwk
- log = logging.getLogger('test')
- class AppleLoginManager(object):
- """
- 苹果登录
- """
- @classmethod
- def get_key(cls, kid):
- """
- 访问 apple 获取公钥. apple 的接口会返回很多公钥的, 根据 jwt 数据 header 的 kid, 找到对应的公钥
- :param kid:
- :return: {
- "kty": "RSA",
- "kid": "eXaunmL",
- "use": "sig",
- "alg": "RS256",
- "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw",
- "e": "AQAB"
- }
- """ ret = requests.get('https://appleid.apple.com/auth/keys')
- ret_json = ret.JSON()
- for key in ret_json['keys']:
- if key['kid'] == kid:
- return key
- log.error(u'[苹果登录] 找不到对应的 kid %s %s' % (kid, ret_json))
- raise Exception('找不到对应的 kid')
- @classmethod
- def verify_jwt(cls, token):
- """
- 验证 jwt 数据, 返回:
- {
- u'c_hash': u'HpjAKvivbJr9j9ZxfFxA',
- u'aud': u'com.test.moe',
- u'iss': u'https://appleid.apple.com',
- u'email_verified': u'true',
- u'nonce_supported': True,
- u'exp': 1583829815,
- u'auth_time': 1583829215,
- u'iat': 1583829215,
- u'email': u'hua@163.com',
- u'sub': u'0017xx.9035989b3bxxxxx7c88b30086b37.xxx' # 用户唯一标志, 相当于 openid
- }
- """
- header, claims = jwt.process_jwt(token) # 获取信息, 但是不验证
- if claims['aud'] != 'com.test.test': # 检验是不是自己的安装包名
- log.error(u'[苹果登录]aud 异常 aud:%s token:%s' % (claims['aud'], token))
- raise Exception(u'安装包名异常')
- key_obj = AppleLoginManager.get_key(header['kid'])
- key = jwk.JWK(**key_obj)
- header, claims = jwt.verify_jwt(token, key, [key_obj['alg']], checks_optional=1) # 获取信息并验证
- return claims
- @classmethod
- def get_access_info(cls, token):
- """获取授权信息"""
- try:
- resp_json = AppleLoginManager.verify_jwt(token)
- return {
- "open_id": resp_json['sub'],
- }
- except:
- log.exception(u'苹果登录异常, token:%s' % token)
- raise Exception('苹果登录异常')
- token = '''xxxx''' #前端传过来的 identity_token
- AppleLoginManager.get_access_info(token)
来源: https://www.cnblogs.com/Xjng/p/12464761.html