pyjwt接入苹果登录

流程图

42e1e777fc8348be018f4ad6482dbcd6

 

 

测试代码:

#coding=utf-8

import jwt
import requests
from datetime import datetime, timedelta
import random
import json

'''
kty:常量标识使用RSA签名算法
kid:密钥id标识
alg:签名算法采用的是RS256(RSA 256 + SHA 256)
n/e:公钥参数,其值采用BASE64编码,使用时需要先解码

完整的payload字符串为:
{
    "iss": "https://appleid.apple.com",
    "aud": "com.aaaaa.bbbbb",
    "exp": 1692757384,
    "iat": 1692670984,
    "sub": "000942.2a81a3fedeaaaaaaa2179fa9b30b2.0223",
    "c_hash": "BJBc4awcx1pCt6OF9Czp9g",
    "email": "qz2bbjwffd@privaterelay.appleid.com",
    "email_verified": "true",
    "is_private_email": "true",
    "auth_time": 1692670984,
    "nonce_supported": true,
    "real_user_status": 2
}
'''

'''
# 创建 JWT
encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
print(encoded_jwt)

# 解码 JWT
decoded_jwt = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
print(decoded_jwt)
'''

# Apple 的公钥服务器地址
APPLE_PUBLIC_KEY_URL = "https://appleid.apple.com/auth/keys"

def jsonStandFormat(jsondata):
    return json.dumps(jsondata, sort_keys=True, indent=4, separators=(',', ':'), ensure_ascii=False)

#从token中获取kid
def get_token_kid(token):
    headers = jwt.get_unverified_header(token)
    kid = headers.get('kid', '')
    print('headers: ')
    print(jsonStandFormat(headers))
    print('')
    
    return kid

#从Apple 获取公钥列表
def get_apple_public_keys():
    response = requests.get(APPLE_PUBLIC_KEY_URL)
    response.raise_for_status()  # 确保请求成功
    results = response.json()['keys']
    
    print('keys: ')
    print(jsonStandFormat(results))
    print('')
    
    return results

#根据token中的kid获取公钥信息
def get_apple_public_key(keys, kid):
    # 选择一个有效的公钥,通常是最近的一个,这里简单取第一个,实际应用中可能需要更复杂的逻辑
    result = [keys[0]['kid'], keys[0]['n'], keys[0]['e']]
    for i, key in enumerate(keys):
        if key['kid'] == kid:
            result = [keys[i]['kid'], keys[i]['n'], keys[i]['e']]
            break;
    
    print('key: ')
    print(jsonStandFormat(result))
    print('')
    
    return result

#验证JWT令牌
def verify_jwt(token):
    kid = get_token_kid(token)
    keys = get_apple_public_keys()
    kid, n, e = get_apple_public_key(keys, kid)
    public_key = "-----BEGIN PUBLIC KEY-----\n%s\n%s\n-----END PUBLIC KEY-----" % (n, e)
    print(public_key)
    print('')
    
    options = {
        "verify_exp": False, 
        "verify_iat": False, 
        "verify_aud": False, 
        "verify_signature": False
    }
    
    try:
        decoded = jwt.decode(token, public_key, algorithms=['RS256'], options=options)  # verify_aud 根据你的配置设置
        return decoded
    except jwt.ExpiredSignatureError:
        print('Token已过期')
    except jwt.InvalidAudienceError:
        print('错误的audience')
    except jwt.InvalidIssuerError:
        print('错误的issuer')
    except jwt.InvalidTokenError:
        print('无效Token')
    except Exception as e:
        print("Token解码失败")
        print(e)
    
    return None

#使用示例
token = "eyJraWQiOiJmaDZCczhDIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnRqZ2QuZGV2ZWxvcC5tb2JpbGV6Lldpc2VUViIsImV4cCI6MTY5MTY0Mzc3MSwiaWF0IjoxNjkxNTU3MzcxLCJzdWIiOiIwMDA0NDAuM2E5M2Y3MDY1NTE0NGY5Mjg5ZGJlY2Q2ODhhMmQxNzguMDc0NSIsImNfaGFzaCI6IjkyOEVmVEliSkVVUDBVQlhNRF9wZHciLCJlbWFpbCI6InRqZ2RpcHR2QGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjoidHJ1ZSIsImF1dGhfdGltZSI6MTY5MTU1NzM3MSwibm9uY2Vfc3VwcG9ydGVkIjp0cnVlfQ.gt1DjUwX5oAzmYyoVoFtqjWv8D3SXkBm327RnadilOQxYbLLM82l45EWozjykRMhMtH4bWsP47m6DtBvwfA13kQg9HNTFCYOdm7j2SnF_3S5m_6sHvaxkK0VDbuk3Z-aWOcMlHMj4kFOdM9EMC5-1Qr_k9y6i7RRmh_xkAoapoFwSlLCb41J9qnornTbZnRT3CMgMngY90uxvlowYj38YpFW5Q1YDEQVtpDTz55yVIN7yPZ5bUlOHgj2wFWp_2IVo2qKCVgC4-qtoxsRDlR_Wghmv5lh_uwMGAkwBcsTS0eP0fGuYPNoZYuYzpiaLV9j3v01N191xgfUzKVa584Zeg"  # 从客户端获取的 JWT 令牌
token_decoded = verify_jwt(token)
print('body: ')
print(jsonStandFormat(token_decoded))
print('')

 

输出:

D:\software\Python27\lib\site-packages\jwt\utils.py:8: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in the next release.
  from cryptography.hazmat.primitives.asymmetric.utils import (
headers: 
{
    "alg":"RS256",
    "kid":"fh6Bs8C"
}

keys: 
[
    {
        "alg":"RS256",
        "e":"AQAB",
        "kid":"E6q83RB15n",
        "kty":"RSA",
        "n":"qD2kjZNSBESRVJksHHnDpMPprhCymecPO8Ji6xlY_fGdUOioVf0nckGaiBwjPGo3xKadAGvbNJ1BjCZOmbLL7lQ5mT8fI6l5HaY8txcz3_PjOUHdiXBuThmQ2eEXtmOtRxi3LNnXaOCpl7QxHgyiPTVgJpJ18Teqz2ESVXg_Lpmw7ot3zBI0p9E56-HVZwxpwS8EoN53nx850fxAlpZj5d1szgV8YzhcRG-8FMOialu-me0OFZWghB-_jCMfdBhWHMWpGkfLPDA1o8eLkr0UByZwMHKCWA--JUvlKvSv3xavDD7ILj8t5PiItonVV9telbza-ToaOWMiG5gZ5QfWDQ",
        "use":"sig"
    },
    {
        "alg":"RS256",
        "e":"AQAB",
        "kid":"Sf2lFqwkpX",
        "kty":"RSA",
        "n":"oNe3ZKHU5-fnmbjhCamUpBSyLkR4jbQy-PCZU4cr7tyPcFokyZ1CjSGm44sw3EPONWO6bWgKZYBX2UPv7UM3GBIuB8qBkkN0_vu0Kdr8KUWJ-6m9fnKgceDil4K4TsSS8Owe9qnP9XjjmVRK7cCEjew4GYqQ7gRcHUjIQ-PrKkNBOOijxLlwckeQK2IN9WS_CBXVMleXLutfYAHpwr2KoAmt5BQvPFqBegozHaTc2UvarcUPKMrl-sjY_AXobH7NjqfbBLRJLzS2EzE4y865QiBpwwdhlK4ZQ3g1DCV57BDKvoBX0guCDNSFvoPuIjMmTxZEUbwrJ1CQ4Ib5j4VCkQ",
        "use":"sig"
    },
    {
        "alg":"RS256",
        "e":"AQAB",
        "kid":"UaIIFY2fW4",
        "kty":"RSA",
        "n":"sxzLtSWjplO4nMymVwkknn6WrQvK4sz7F1rrIwOKPa3SpltaB719cfxFfoE4UqHfVxHXsoYew82ViYz5whp0CuqgWi2t4HYpSTCQdVCNIXpsMxA8QqTfIlc-EUFNuUMziY-hJXqi4i-woI0HiwPEkO-AhWy86L9-J_1I1yw22-BICacAU7J9UTBBwHu0wkRHiyPe4pHow1wa91v5OM09XHqjHpiFrJD7bOBl6Y3EuBXEWy3VEA-S2IchqVGmvNGNZo6J9WtSHEcL6ussFWPJoIo2GR4BrgHvZGUvhgbHrKjCPrIAhliH0er3pF5_0UTSqW0Xg_Q2iQpxo9TRn-kHpw",
        "use":"sig"
    }
]

key: 
[
    "E6q83RB15n",
    "qD2kjZNSBESRVJksHHnDpMPprhCymecPO8Ji6xlY_fGdUOioVf0nckGaiBwjPGo3xKadAGvbNJ1BjCZOmbLL7lQ5mT8fI6l5HaY8txcz3_PjOUHdiXBuThmQ2eEXtmOtRxi3LNnXaOCpl7QxHgyiPTVgJpJ18Teqz2ESVXg_Lpmw7ot3zBI0p9E56-HVZwxpwS8EoN53nx850fxAlpZj5d1szgV8YzhcRG-8FMOialu-me0OFZWghB-_jCMfdBhWHMWpGkfLPDA1o8eLkr0UByZwMHKCWA--JUvlKvSv3xavDD7ILj8t5PiItonVV9telbza-ToaOWMiG5gZ5QfWDQ",
    "AQAB"
]

-----BEGIN PUBLIC KEY-----
qD2kjZNSBESRVJksHHnDpMPprhCymecPO8Ji6xlY_fGdUOioVf0nckGaiBwjPGo3xKadAGvbNJ1BjCZOmbLL7lQ5mT8fI6l5HaY8txcz3_PjOUHdiXBuThmQ2eEXtmOtRxi3LNnXaOCpl7QxHgyiPTVgJpJ18Teqz2ESVXg_Lpmw7ot3zBI0p9E56-HVZwxpwS8EoN53nx850fxAlpZj5d1szgV8YzhcRG-8FMOialu-me0OFZWghB-_jCMfdBhWHMWpGkfLPDA1o8eLkr0UByZwMHKCWA--JUvlKvSv3xavDD7ILj8t5PiItonVV9telbza-ToaOWMiG5gZ5QfWDQ
AQAB
-----END PUBLIC KEY-----

body: 
{
    "aud":"com.tjgd.develop.mobilez.WiseTV",
    "auth_time":1691557371,
    "c_hash":"928EfTIbJEUP0UBXMD_pdw",
    "email":"tjgdiptv@gmail.com",
    "email_verified":"true",
    "exp":1691643771,
    "iat":1691557371,
    "iss":"https://appleid.apple.com",
    "nonce_supported":true,
    "sub":"000440.3a93f70655144f9289dbecd688a2d178.0745"
}

 

参考:

https://huaweicloud.csdn.net/64eea46cc70554103b8eafb7.html?dp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6NjMzNDQ3LCJleHAiOjE3NTQzODk0NTQsImlhdCI6MTc1Mzc4NDY1NCwidXNlcm5hbWUiOiJ3ZWl4aW5fNDQyMDY5OTMifQ.kYZhDyXAGM8HjJUeIXxyq686W1IPPKopJUhK4yzEak0&spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-4-106122067-blog-147565203.235%5Ev43%5Econtrol&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-4-106122067-blog-147565203.235%5Ev43%5Econtrol&utm_relevant_index=9

https://pyjwt.readthedocs.io/en/stable/

posted @ 2025-07-30 11:33  河北大学-徐小波  阅读(267)  评论(0)    收藏  举报