Python 解密JWT驗證蘋果登錄


  1. 驗證蘋果登錄,官方提供兩種驗證方法,一種是token,另一個種是code。這里使用的是token

  2. 登錄流程:

    1. 蘋果客戶端調用蘋果API,獲取到用戶的信息,包括:
      1. user_id
      2. 昵稱
      3. identity_token
    2. 蘋果客戶端發送identity_token到服務端
    3. 服務端驗證identity_token是否合法,並解析數據,得到user_id。這個user_id和上面的user_id是一樣的
    4. 服務端檢查該user_id是否已注冊,如果是,返回登錄信息。如果否,注冊。
  3. 驗證的原理:

    1. 蘋果會把用戶的信息放在一個json里面,然后使用私鑰對json簽名。
    2. 服務端調用蘋果API拿到公鑰,然后驗證簽名是否正確。
    3. 所以總的來說就是使用RSA私鑰簽名的算法來保證數據不會被篡改。
  4. identity_token解析后包含幾部分內容

    1. header。
      1. 例子:{u'alg': u'RS256', u'kid': u'86D88Kf'}
      2. alg是加密算法類型
      3. kid是使用的公鑰的id
    2. payload或者claims 。也就是數據:
      1. 例子:
		{
         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
       }
	17. aud 客戶端的報名。
	18. exp。超時時間,時間戳。當前時間如果大於這個時間,會報超時錯誤
	19. email 用戶的email
	20. 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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM