一个框架无关的统一第三方登录 Python SDK,提供简单、一致的多平台 OAuth2 登录集成方案。
- 🔹 框架无关:不依赖特定 Web 框架,可用于 Flask、FastAPI、Django 等
- 🔹 插件式架构:支持动态扩展新的 Provider
- 🔹 统一接口:所有平台提供一致的 API 调用方式
- 🔹 轻量依赖:仅依赖
requests和pydantic - 🔹 类型安全:完整的 TypeScript 风格类型注解
- 🔹 生产就绪:包含重试机制、错误处理、日志记录
| 平台 | 状态 | Provider 名称 |
|---|---|---|
| GitHub | ✅ 已支持 | github |
| 微信 | ✅ 已支持 | wechat |
| ✅ 已支持 | qq |
|
| 支付宝 | 🚧 计划中 | alipay |
| 🚧 计划中 | google |
pip install unilogin-py开发版本:
pip install unilogin-py[dev]from unilogin.factory import get_provider
# 创建 GitHub Provider
provider = get_provider(
"github",
client_id="your_github_client_id",
client_secret="your_github_client_secret",
redirect_uri="http://localhost:5000/callback/github"
)
# 生成授权链接
auth_url = provider.get_auth_url(state="random_state_string")
print(f"请访问: {auth_url}")
# 处理回调,获取用户信息
code = "从回调 URL 中获取的 code 参数"
token_info = provider.get_access_token(code)
user_info = provider.get_user_info(token_info.access_token)
print(f"用户信息: {user_info.model_dump_json(indent=2)}")from flask import Flask, redirect, request, jsonify, session
from unilogin.factory import get_provider
from unilogin.core.exceptions import UniLoginError
import secrets
app = Flask(__name__)
app.secret_key = "your-secret-key"
# 配置信息
PROVIDERS_CONFIG = {
"github": {
"client_id": "your_github_client_id",
"client_secret": "your_github_client_secret",
"redirect_uri": "http://localhost:5000/callback/github"
}
}
@app.route("/login/<provider_name>")
def login(provider_name):
"""发起登录"""
try:
config = PROVIDERS_CONFIG.get(provider_name)
if not config:
return jsonify({"error": f"不支持的 Provider: {provider_name}"}), 400
provider = get_provider(provider_name, **config)
state = secrets.token_urlsafe(32)
session[f"{provider_name}_state"] = state
auth_url = provider.get_auth_url(state=state)
return redirect(auth_url)
except UniLoginError as e:
return jsonify({"error": str(e)}), 400
@app.route("/callback/<provider_name>")
def callback(provider_name):
"""处理登录回调"""
try:
config = PROVIDERS_CONFIG.get(provider_name)
provider = get_provider(provider_name, **config)
# 验证 state 参数
state = request.args.get("state")
expected_state = session.get(f"{provider_name}_state")
if state != expected_state:
return jsonify({"error": "Invalid state parameter"}), 400
code = request.args.get("code")
if not code:
return jsonify({"error": "Missing authorization code"}), 400
# 获取访问令牌和用户信息
token_info = provider.get_access_token(code)
user_info = provider.get_user_info(token_info.access_token)
return jsonify({
"message": "登录成功",
"user": user_info.model_dump(),
"token": token_info.model_dump()
})
except UniLoginError as e:
return jsonify({"error": str(e)}), 400
if __name__ == "__main__":
app.run(debug=True)创建指定的 Provider 实例。
参数:
name: Provider 名称(如 "github", "wechat", "qq")client_id: OAuth2 客户端 IDclient_secret: OAuth2 客户端密钥redirect_uri: 授权回调地址
get_auth_url(state: str = "") -> str: 生成授权链接get_access_token(code: str) -> TokenInfo: 获取访问令牌get_user_info(access_token: str, **kwargs) -> UserInfo: 获取用户信息
class UserInfo(BaseModel):
id: str # 第三方平台用户唯一标识
nickname: str # 用户昵称
avatar: Optional[str] # 用户头像 URL
gender: Optional[str] # 用户性别
email: Optional[str] # 用户邮箱
provider: str # 平台名称
raw_data: Optional[dict] # 原始数据
created_at: datetime # 创建时间class TokenInfo(BaseModel):
access_token: str # 访问令牌
token_type: str # 令牌类型
expires_in: Optional[int] # 过期时间(秒)
refresh_token: Optional[str] # 刷新令牌
scope: Optional[str] # 授权范围
raw_data: Optional[dict] # 原始响应数据
created_at: datetime # 创建时间from unilogin.core.base_provider import BaseProvider
from unilogin.core.models import UserInfo, TokenInfo
from unilogin.factory import register_provider
class CustomProvider(BaseProvider):
@property
def provider_name(self) -> str:
return "custom"
@property
def auth_url(self) -> str:
return "https://custom.com/oauth/authorize"
@property
def token_url(self) -> str:
return "https://custom.com/oauth/token"
@property
def user_info_url(self) -> str:
return "https://custom.com/api/user"
def get_auth_url(self, state: str = "", **kwargs) -> str:
# 实现授权链接生成逻辑
pass
def get_access_token(self, code: str, **kwargs) -> TokenInfo:
# 实现令牌获取逻辑
pass
def get_user_info(self, access_token: str, **kwargs) -> UserInfo:
# 实现用户信息获取逻辑
pass
# 注册新 Provider
register_provider("custom", CustomProvider)# 安装开发依赖
pip install -e .[dev]
# 运行测试
pytest
# 运行测试并生成覆盖率报告
pytest --cov=unilogin --cov-report=html
# 代码格式化
black unilogin/
isort unilogin/
# 类型检查
mypy unilogin/本项目采用 MIT 许可证。
欢迎贡献代码!请查看 贡献指南 了解详细信息。
- v0.3.0: 新增支付宝 Provider
- v0.4.0: FastAPI 集成 & 缓存机制
- v1.0.0: 稳定版发布,PyPI 上架