文章
使用Github第三方登录完整流程
总体流程如下: 用户点击登录 → 跳转 GitHub → 授权 → 回调 code → 后端换 token → 拉取用户信息 → 生成 JWT → 重定向前端 → 前端保存 JWT → 后续 API 调用
目录
使用 GitHub 进行第三方登录(OAuth2)的完整流程整理如下,以 Actix + Rust + JWT 的实现为示例。#
1️⃣ 准备工作#
- 注册 GitHub OAuth App
- 地址:https://github.com/settings/developers

- 填写:
- Application name: 项目名称
- Homepage URL: 前端主页,如
http://localhost:3000 - Authorization callback URL: GitHub 登录后重定向的后端 URL,如
http://localhost:8000/auth/github/callback
- 获取:
Client IDClient Secret
- 地址:https://github.com/settings/developers
- 后端环境变量
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETFRONTEND_URL(前端页面 URL,用于登录成功后跳转)DATABASE_URL(可选,如果存用户信息)
2️⃣ 登录入口#
用户点击 “使用 GitHub 登录” 按钮:
- 后端生成 OAuth2 授权 URL:
- 包含:
client_idredirect_uri(回调地址)scope(请求权限,如user:email)state(防 CSRF,可随机字符串)code_challenge(如果使用 PKCE)
- 包含:
- 返回这个 URL 给前端,前端跳转到 GitHub 授权页面。
// Actix 例子
let (auth_url, csrf_state, pkce_code_challenge) = client
.authorize_url(CsrfToken::new_random)
.add_scope(Scope::new("user:email".to_string()))
.set_pkce_challenge(PkceCodeChallenge::from_code_verifier(&pkce_verifier))
.url();
3️⃣ 用户授权#
- 用户在 GitHub 页面点击 Authorize。
- GitHub 验证通过后,重定向到你的 callback URL:
GET /auth/github/callback?code=xxxx&state=xxxx ```#
4️⃣ 后端换取 Github Access Token#
- 后端收到
code和state。 - 验证
state是否和之前生成的一致(防 CSRF)。 - 如果使用 PKCE,需要使用
code_verifier。 - 请求 GitHub Token 接口:
let token_res = client
.exchange_code(AuthorizationCode::new(code.to_string()))
.set_pkce_verifier(pkce_verifier)
.request_async(oauth2::reqwest::async_http_client)
.await;
- 返回:
access_tokenscopetoken_type
如果失败,就返回错误给前端(JSON + UTF-8),不要直接显示中文文本,避免乱码。
5️⃣ 使用Github Access Token获取Github的用户信息#
let user_res = HTTP
.get("https://api.github.com/user")
.bearer_auth(token.access_token().secret())
.header("User-Agent", "your-app-name")
.send()
.await?;
- 获取:
login/id/name/avatar_url/email等
- 如果邮箱为空,还可以调用:
GET https://api.github.com/user/emails
6️⃣ 生成自己应用系统的JWT(无需 session)#
- 使用用户信息生成 JWT:
let jwt = generate_jwt(&user);
- JWT 可以包含:
- 用户 ID
- 登录来源(GitHub)
- 过期时间
- 后端不再维护 session,前端保存 JWT(localStorage / cookie)。
7️⃣ 重定向到前端#
- 登录成功后,重定向到前端页面,并带上 JWT:
let frontend_url = env::var("FRONTEND_URL").unwrap_or_else(|_| "http://localhost:3000".to_string());
let url = format!("{frontend_url}?token={jwt}");
HttpResponse::Found()
.append_header(("Location", url))
.finish();
最后浏览器就会跳转,如下链接去访问前端资源,并在地址栏传递参数
http://localhost:3000?token=eyJhbGciOi...
⚠️ 注意: - 如果 JWT 里有中文信息,要保证 HTTP header
Content-Type或 JSON 返回中charset=utf-8,否则浏览器显示乱码。 - 前端拿到 JWT 后解析,存入 localStorage 或 cookie 进行后续 API 调用认证。
8️⃣ 前端获取并使用JWT 调用 API#
- 前端从 URL(也就是上一节说的后端跳转的FRONTEND_URL) 获取 JWT。
import { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
export function OAuthCallbackHandler() {
const location = useLocation();
const navigate = useNavigate();
useEffect(() => {
const params = new URLSearchParams(location.search);
const token = params.get("token");
if (token) {
// 存储到 localStorage 或 sessionStorage
localStorage.setItem("access_token", token);
// 移除 URL 上的敏感 token,防止被历史记录
navigate("/", { replace: true });
}
}, [location, navigate]);
return <div>登录中,请稍候...</div>;
}