title: 如何在FastAPI中玩转GitHub认证,让用户一键登录?
date: 2025/06/22 09:11:47
updated: 2025/06/22 09:11:47
author: cmdragon
excerpt:
GitHub第三方认证集成通过OAuth2.0授权码流程实现,包含用户跳转GitHub认证、获取授权码、交换访问令牌及调用API获取用户信息四个步骤。首先需在GitHub注册应用,获取CLIENT_ID和CLIENT_SECRET。使用FastAPI实现认证流程,包括初始化认证、处理回调、生成JWT令牌及验证用户。安全措施包括使用state参数防止CSRF攻击和正确配置Authorization头。常见问题如redirect_uri不匹配、invalid_state错误和JWT解码失败,需检查回调地址、state一致性和SECRET_KEY配置。
categories:
tags:
扫描二维码
关注或者微信搜一搜:编程智域 前端至全栈交流与成长
发现1000+提升效率与开发的AI工具和实用程序:https://tools.cmdragon.cn/
在FastAPI中集成GitHub认证需要理解OAuth2.0授权码流程,该流程包含四个核心步骤:
整个过程如同酒店入住流程:用户出示身份证(GitHub登录)→ 获得临时房卡(授权码)→ 换取正式房卡(访问令牌)→ 享受酒店服务(API调用)
在实施前需要完成GitHub应用注册:
获取关键凭证:
CLIENT_ID = "your_github_client_id"
CLIENT_SECRET = "your_github_client_secret"
安装所需依赖(推荐使用虚拟环境):
pip install fastapi==0.103.1 uvicorn==0.23.2 python-multipart==0.0.6 httpx==0.25.0 python-jose[cryptography]==3.3.0
完整认证代码示例:
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import JWTError, jwt
from pydantic import BaseModel
import httpx
app = FastAPI()
# 配置模型
class AuthConfig(BaseModel):
client_id: str = CLIENT_ID
client_secret: str = CLIENT_SECRET
redirect_uri: str = "http://localhost:8000/auth/github/callback"
token_url: str = "https://github.com/login/oauth/access_token"
user_url: str = "https://api.github.com/user"
# JWT配置
SECRET_KEY = "your-secret-key-123"
ALGORITHM = "HS256"
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl="https://github.com/login/oauth/authorize",
tokenUrl="https://github.com/login/oauth/access_token"
)
@app.get("/auth/github")
async def github_login():
"""初始化GitHub认证流程"""
return {
"auth_url": f"https://github.com/login/oauth/authorize?client_id={CLIENT_ID}"
}
@app.get("/auth/github/callback")
async def github_callback(code: str):
"""处理GitHub回调"""
async with httpx.AsyncClient() as client:
# 交换访问令牌
token_response = await client.post(
"https://github.com/login/oauth/access_token",
data={
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"code": code
},
headers={"Accept": "application/json"}
)
access_token = token_response.json().get("access_token")
if not access_token:
raise HTTPException(status_code=400, detail="认证失败")
# 获取用户信息
user_response = await client.get(
"https://api.github.com/user",
headers={"Authorization": f"Bearer {access_token}"}
)
user_data = user_response.json()
return generate_jwt(user_data)
def generate_jwt(user_data: dict):
"""生成JWT令牌"""
token_data = {
"sub": user_data["login"],
"id": user_data["id"],
"avatar": user_data["avatar_url"]
}
return {
"access_token": jwt.encode(token_data, SECRET_KEY, algorithm=ALGORITHM),
"token_type": "bearer"
}
async def get_current_user(token: str = Depends(oauth2_scheme)):
"""JWT验证依赖项"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无效的凭证",
headers={"WWW-Authenticate": "Bearer"},
)
@app.get("/protected")
async def protected_route(user: dict = Depends(get_current_user)):
"""需要认证的端点示例"""
return {"message": f"欢迎,{user['sub']}!"}
在正式环境中必须配置以下安全参数:
# 在AuthConfig中添加
state: str = "random_anti_csrf_string"
scope: str = "user:email"
# 修改认证URL
auth_url = f"https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&state={state}&scope={scope}"
答案:B。state参数用于防止跨站请求伪造攻击,服务器会验证请求和回调中的state值是否一致。
答案:C。Authorization头正确携带Bearer token是保证认证安全的关键,需要配合HTTPS使用。
问题1:redirect_uri_mismatch
error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match...
解决方案:
问题2:invalid_state参数错误
解决方案:
问题3:JWT解码失败
jose.exceptions.JWTError: Signature verification failed
解决方案:
余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:如何在FastAPI中玩转GitHub认证,让用户一键登录? | cmdragon's Blog
登录查看全部
参与评论
手机查看
返回顶部