谷歌access token授权码认证.md 8.2 KB

#python #unity/日常积累

谷歌game service v2 版本,会返回授权码: auth_code (str): Google授权码(以4/开头的字符串)

在执行相关逻辑之前,确保安装了,python库中,谷歌认证相关:

 pip install google-auth requests

另外,还需要准备的材料:

![[Pasted image 20250620103522.png]]

google_token.py

import requests
import json
import sys
from google.oauth2 import id_token
from google.auth.transport import requests as google_requests

def exchange_auth_code(auth_code, client_id, client_secret):
    """
    用授权码交换获取访问令牌和ID令牌
    
    参数:
        auth_code (str): Google授权码(以4/开头的字符串)
        client_id (str): 你的Google OAuth客户端ID
        client_secret (str): 你的Google OAuth客户端密钥
        
    返回:
        dict: 包含tokens和用户信息的字典
    """
    token_url = "https://oauth2.googleapis.com/token"
    payload = {
        "code": auth_code,
        "client_id": client_id,
        "client_secret": client_secret,
        "redirect_uri": "http://localhost",
        "grant_type": "authorization_code"
    }
    
    print(f"正在交换授权码...")
    try:
        response = requests.post(token_url, data=payload)
        
        if response.status_code == 200:
            token_data = response.json()
            print(f"令牌交换成功!")
            
            # 获取各种令牌
            access_token = token_data.get("access_token")
            id_token_str = token_data.get("id_token")
            refresh_token = token_data.get("refresh_token")
            
            # 安全地打印令牌信息,避免NoneType错误
            if access_token:
                print(f"\n访问令牌(Access Token): {access_token[:20]}...(已截断)")
            else:
                print("\n访问令牌(Access Token): None")
                
            if id_token_str:
                print(f"ID令牌(ID Token): {id_token_str[:20]}...(已截断)")
            else:
                print("ID令牌(ID Token): None")
                
            if refresh_token:
                print(f"刷新令牌(Refresh Token): {refresh_token[:20]}...(已截断)")
            else:
                print("刷新令牌(Refresh Token): None")
            
            # 保存完整令牌到文件以备后用
            try:
                with open("tokens.json", "w") as f:
                    json.dump(token_data, f, indent=2)
                    print(f"\n已将完整令牌保存到 tokens.json 文件")
            except Exception as e:
                print(f"保存令牌到文件失败: {e}")
            
            # 验证ID令牌并获取用户信息
            if id_token_str:
                try:
                    user_info = verify_id_token(id_token_str, client_id)
                    return {
                        "tokens": token_data,
                        "user_info": user_info
                    }
                except Exception as e:
                    print(f"ID令牌验证失败: {e}")
                    return {
                        "tokens": token_data,
                        "user_info": None
                    }
            else:
                print("响应中没有ID令牌")
                return {
                    "tokens": token_data,
                    "user_info": None
                }
        else:
            print(f"错误: {response.status_code}")
            print(response.text)
            return None
    except Exception as e:
        print(f"请求过程中发生错误: {e}")
        return None

def verify_id_token(id_token_str, client_id):
    """
    验证ID令牌并返回用户信息
    
    参数:
        id_token_str (str): 要验证的ID令牌
        client_id (str): 你的Google OAuth客户端ID
        
    返回:
        dict: 用户信息字典
    """
    print(f"\n正在验证ID令牌...")
    try:
        idinfo = id_token.verify_oauth2_token(
            id_token_str, 
            google_requests.Request(), 
            client_id
        )
        
        # 验证发行者
        if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
            raise ValueError('错误的令牌发行者.')
        
        print(f"ID令牌验证成功!")
        return idinfo
    except Exception as e:
        print(f"ID令牌验证失败: {e}")
        raise

def get_user_info_from_token(access_token):
    """
    使用访问令牌获取用户信息
    
    参数:
        access_token (str): 访问令牌
        
    返回:
        dict: 用户信息字典
    """
    if not access_token:
        print("访问令牌为空,无法获取用户信息")
        return None
        
    print(f"\n使用访问令牌获取用户信息...")
    
    userinfo_url = "https://openidconnect.googleapis.com/v1/userinfo"
    headers = {
        "Authorization": f"Bearer {access_token}"
    }
    
    try:
        response = requests.get(userinfo_url, headers=headers)
        
        if response.status_code == 200:
            user_info = response.json()
            print(f"获取用户信息成功!")
            return user_info
        else:
            print(f"获取用户信息失败: {response.status_code}")
            print(response.text)
            return None
    except Exception as e:
        print(f"获取用户信息过程中发生错误: {e}")
        return None

def main():
    """主函数,处理命令行参数并执行令牌交换"""
    try:
        if len(sys.argv) < 4:
            print("用法: python exchange_code.py <授权码> <客户端ID> <客户端密钥>")
            sys.exit(1)
        
        auth_code = sys.argv[1]
        client_id = sys.argv[2]
        client_secret = sys.argv[3]
        
        # 安全地截断显示参数
        auth_code_display = auth_code[:10] + "...(已截断)" if len(auth_code) > 10 else auth_code
        client_id_display = client_id[:15] + "...(已截断)" if len(client_id) > 15 else client_id
        client_secret_display = client_secret[:5] + "...(已截断)" if len(client_secret) > 5 else client_secret
        
        print("-" * 50)
        print("Google授权码交换工具")
        print("-" * 50)
        print(f"授权码: {auth_code_display}")
        print(f"客户端ID: {client_id_display}")
        print(f"客户端密钥: {client_secret_display}")
        print("-" * 50)
        
        result = exchange_auth_code(auth_code, client_id, client_secret)
        
        if result:
            tokens = result.get("tokens", {})
            user_info = result.get("user_info")
            
            # 如果ID令牌验证失败,尝试使用访问令牌获取用户信息
            if not user_info and tokens.get("access_token"):
                user_info = get_user_info_from_token(tokens["access_token"])
            
            if user_info:
                print("\n----- 用户信息 -----")
                print(f"用户ID: {user_info.get('sub') or user_info.get('id', 'N/A')}")
                print(f"电子邮件: {user_info.get('email', 'N/A')}")
                print(f"姓名: {user_info.get('name', 'N/A')}")
                print(f"头像: {user_info.get('picture', 'N/A')}")
                
                # 保存用户信息到文件
                try:
                    with open("user_info.json", "w") as f:
                        json.dump(user_info, f, indent=2)
                        print(f"\n已将用户信息保存到 user_info.json 文件")
                except Exception as e:
                    print(f"保存用户信息到文件失败: {e}")
            else:
                print("\n无法获取用户信息")
        else:
            print("\n令牌交换失败")
            sys.exit(1)
        
        print("\n处理完成!")
    except Exception as e:
        print(f"程序执行过程中发生错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main() 

调用方式

python .\google_token.py 4/0AUJR-x5Sbmm9wToj9ai84DdPRf-FaubSQieqnV0k2OWkVeqGg_XW08bGgyMDIxoTilbH3A 956550854222-pfjuen977e59l6hif1tj08bibh93tguu.apps.googleusercontent.com AIzaSyDLJnWUHh6o-F4e9N0fUsbGeS2sIoqyLr4

传参分别是:授权码、web客户端ID、web客户端密钥

![[Pasted image 20250620103712.png]]