在这篇教程中,我们将介绍如何在多端(如微信小程序、移动应用等)实现 Apple OAuth 登录,并提供简单的代码示例。
1.回调处理 - 获取授权码并交换令牌
当用户授权后,Apple 会回调你设置的 URL(如 apple_callback/
)。后端会接收授权码并请求令牌。
@skip_jwt_authentication
def apple_callback(request):
"""
Apple OAuth 回调处理
"""
code = request.POST.get('code') # 获取授权码
if not code:
return JsonResponse({'code': 4003, 'message': "缺少授权码"}, status=400)
# 请求 Apple token
client_secret = generate_apple_client_secret() # 生成 client_secret
token_url = "https://appleid.apple.com/auth/token"
token_data = {
'client_id': settings.APPLE_CLIENT_ID,
'client_secret': client_secret,
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': settings.APPLE_REDIRECT_URI,
}
try:
token_response = requests.post(token_url, data=token_data)
token_response.raise_for_status() # 如果请求失败,会抛出异常
# 解析 token
token_info = token_response.json()
id_token = token_info.get('id_token')
if not id_token:
return JsonResponse({'code': 4004, 'message': '未收到 id_token'}, status=400)
# 解码 id_token 并提取信息
decoded_id_token = jwt.decode(
id_token,
get_apple_public_key(id_token),
audience=settings.APPLE_CLIENT_ID,
issuer="https://appleid.apple.com",
algorithms=["RS256"]
)
apple_user_id = decoded_id_token.get('sub')
email = decoded_id_token.get('email')
# 查找或创建用户
user, created = CustomUser.objects.get_or_create(
apple_id=apple_user_id,
defaults={'email': email, 'is_active': False} # 默认信息
)
# 返回 JWT token 和用户信息
jwt_token = JWTAuthentication.generate_jwt_token(user)
user_data = user.get_user_profile_data()
profile_complete = user.is_active
return render(request, 'app/apple_success.html', {
'jwt_token': jwt_token,
'userInfo': json.dumps(user_data),
'profile_complete': json.dumps(profile_complete)
})
except requests.exceptions.RequestException as e:
return JsonResponse({'code': 5001, 'message': 'Apple token 请求失败'}, status=500)
except jwt.exceptions.InvalidTokenError as e:
return JsonResponse({'code': 4006, 'message': 'id_token 解码失败'}, status=400)
2.用于验证 id_token
:
def generate_apple_client_secret():
"""
生成 Apple OAuth 2.0 client_secret
"""
headers = {
"alg": "ES256",
"kid": settings.APPLE_KEY_ID # 替换为你的 APPLE_KEY_ID
}
payload = {
"iss": settings.APPLE_TEAM_ID, # 替换为你的 APPLE_TEAM_ID
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(days=180),
"aud": "https://appleid.apple.com",
"sub": settings.APPLE_CLIENT_ID # 替换为你的 APPLE_CLIENT_ID
}
client_secret = jwt.encode(
payload,
settings.APPLE_PRIVATE_KEY, # 替换为你的 APPLE_PRIVATE_KEY
algorithm="ES256",
headers=headers
)
return client_secret
def get_apple_public_key(id_token):
"""
获取 Apple 公钥用于验证 id_token
"""
try:
apple_keys = requests.get("https://appleid.apple.com/auth/keys").json()
headers = jwt.get_unverified_header(id_token)
key = next((k for k in apple_keys['keys'] if k["kid"] == headers["kid"]), None)
if key:
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key)
return public_key
else:
raise ValueError("未找到匹配的 Apple 公钥")
except Exception as e:
raise ValueError("未找到匹配的 Apple 公钥")
3.前端 - 启动 WebView 打开 Apple 登录
appleLogin() {
console.log("Apple 登录触发");
// 构建 Apple 登录 URL
const appleLoginUrl = `https://appleid.apple.com/auth/authorize?client_id=客户端ID 在苹果开发者后台找到&redirect_uri=https://回调域名/&response_type=code&scope=name email&state=random_string_to_ensure_request_integrity&response_mode=form_post`;
// 使用 WebView 打开 Apple 登录页面
app.openWebViewPage(appleLoginUrl);
}
需要填写的内容:
- client_id:替换为你的 Apple 客户端 ID。
- redirect_uri:替换为你的回调 URL,通常是处理授权码的后端接口 URL。
总结
通过以上步骤,你可以实现 Apple 登录功能。后端负责生成认证 URL 和处理回调,前端通过 WebView 跳转到认证页面,用户认证后,后端接收授权码并交换令牌,最终完成用户登录过程。
在ios设备上就实现一点击出现人脸识别就可以登录你的app了