以下是使用 Authlib 和 FastAPI 实现 GitHub OAuth 登录的完整示例:
from authlib.integrations.starlette_client import OAuth
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, RedirectResponse
from starlette.config import Config
from starlette.middleware.sessions import SessionMiddleware
# 配置
config = Config('.env')
oauth = OAuth(config)
CONF_URL = 'https://github.com/login/oauth/authorize'
GITHUB_CLIENT_ID = "你的GitHub Client ID"
GITHUB_CLIENT_SECRET = "你的GitHub Client Secret"
# 注册 GitHub OAuth
oauth.register(
name='github',
client_id=GITHUB_CLIENT_ID,
client_secret=GITHUB_CLIENT_SECRET,
access_token_url='https://github.com/login/oauth/access_token',
access_token_params=None,
authorize_url='https://github.com/login/oauth/authorize',
authorize_params=None,
api_base_url='https://api.github.com/',
client_kwargs={'scope': 'user:email'},
)
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from .oauth import oauth
app = FastAPI()
# 添加 session 中间件
app.add_middleware(
SessionMiddleware,
secret_key="你的session密钥"
)
# CORS 配置
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], # 前端域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get('/api/auth/login/github')
async def github_login(request: Request):
# 生成用于防止CSRF攻击的state
redirect_uri = request.url_for('github_callback')
return await oauth.github.authorize_redirect(request, redirect_uri)
@app.get('/api/auth/callback/github')
async def github_callback(request: Request):
try:
token = await oauth.github.authorize_access_token(request)
resp = await oauth.github.get('user', token=token)
user = resp.json()
# 获取用户邮箱
emails_resp = await oauth.github.get('user/emails', token=token)
emails = emails_resp.json()
primary_email = next(
(email['email'] for email in emails if email['primary']),
None
)
# 构建用户信息
user_data = {
'id': user['id'],
'login': user['login'],
'name': user['name'],
'email': primary_email,
'avatar_url': user['avatar_url'],
'access_token': token['access_token']
}
# 存储用户信息到session
request.session['user'] = user_data
# 重定向到前端
frontend_url = "http://localhost:3000" # 前端URL
return RedirectResponse(
url=f"{frontend_url}/auth/callback?token={token['access_token']}"
)
except Exception as e:
return JSONResponse(
status_code=400,
content={'error': str(e)}
)
@app.get('/api/auth/user')
async def get_user(request: Request):
user = request.session.get('user')
if not user:
return JSONResponse(
status_code=401,
content={'error': 'Not authenticated'}
)
return user
@app.post('/api/auth/logout')
async def logout(request: Request):
request.session.pop('user', None)
return {'message': 'Successfully logged out'}
前端实现示例(React):
import React from 'react';
export const GithubLogin: React.FC = () => {
const handleLogin = () => {
// 打开新窗口进行 GitHub 授权
const width = 600;
const height = 600;
const left = window.screen.width / 2 - width / 2;
const top = window.screen.height / 2 - height / 2;
window.open(
'/api/auth/login/github',
'GitHub Login',
`width=${width},height=${height},top=${top},left=${left}`
);
};
return (
<button onClick={handleLogin}>
使用 GitHub 登录
</button>
);
};
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
export const AuthCallback: React.FC = () => {
const navigate = useNavigate();
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const token = params.get('token');
if (token) {
// 存储 token
localStorage.setItem('token', token);
// 通知父窗口登录成功
if (window.opener) {
window.opener.postMessage({ type: 'AUTH_SUCCESS', token }, '*');
window.close();
} else {
// 如果不是弹窗,则重定向
navigate('/');
}
}
}, [navigate]);
return null;
};
环境变量配置 (.env):
GITHUB_CLIENT_ID=你的GitHub Client ID
GITHUB_CLIENT_SECRET=你的GitHub Client Secret
SECRET_KEY=你的session密钥
使用说明:
- 安装依赖:
pip install fastapi uvicorn authlib httpx python-dotenv python-jose[cryptography]
在 GitHub 开发者设置中:
- 创建 OAuth App
- 设置回调 URL 为
http://localhost:8000/api/auth/callback/github
- 获取 Client ID 和 Client Secret
主要功能:
/api/auth/login/github
: 开始 GitHub 登录流程/api/auth/callback/github
: GitHub 回调处理/api/auth/user
: 获取当前登录用户信息/api/auth/logout
: 登出
安全考虑:
- 使用 session 存储用户信息
- 实现了 CSRF 保护
- 支持 CORS
- 使用 HTTPS(生产环境)
- 启动服务:
uvicorn app.main:app --reload
这个实现:
- 支持前后端分离
- 处理了 GitHub OAuth 流程
- 包含了错误处理
- 提供了用户会话管理
- 支持弹窗和重定向两种方式
Comments | NOTHING