📅  最后修改于: 2023-12-03 15:06:46.288000             🧑  作者: Mango
在现代应用程序中,认证和授权是一个重要的组成部分,Google 身份验证为用户提供了一种安全可靠的身份验证方式。本篇文章将介绍如何使用 FastAPI 和 ReactJS 实现服务器端的 Google 身份验证。
在开始本文之前,您需要先准备以下环境/工具:
在 GCP 中创建一个新的项目,并启用 Google 身份验证 API。
登录 Google Cloud Console,创建一个新的项目或者使用已有的项目。
在项目中启用 Google 身份验证 API。在导航栏中选择“API 和服务”,然后选择“库”。
在搜索框中输入“Google 身份验证”,然后选择“Google 身份验证 API”。
点击“启用”。
创建 OAuth 2.0 客户端 ID。在导航栏中选择“API 和服务”,然后选择“凭据”。
在创建凭据界面中,选择“Web 应用程序”。
在“授权 JavaScript 来源”和“授权重定向 URI”中分别输入您的应用程序的 URL。
创建完成后,您将获得一个客户端 ID 和客户端密钥,这些信息将在后面的代码中用到。
创建一个新的项目文件夹,并在其中创建一个名为“backend”的新文件夹。
在“backend”文件夹中创建一个名为“main.py”的 Python 脚本,并安装 FastAPI 和 Google APIs Client Library for Python。
# 创建 backend 文件夹
$ mkdir backend
$ cd backend
# 创建 main.py 文件
$ touch main.py
# 安装 FastAPI 和 Google APIs Client Library for Python
$ pip install fastapi google-api-python-client
将以下代码粘贴到“main.py”中,并填入您的应用程序的客户端 ID 和客户端密钥。
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from google.oauth2 import id_token
from google.auth.transport import requests
app = FastAPI()
origins = [
"http://localhost",
"http://localhost:3000",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def read_root():
html_content = """
<html>
<body>
<h1>Google 身份验证</h1>
<p>这是一个使用 Google 身份验证的实例。</p>
<a href="/login/google">使用 Google 账号登录</a>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
@app.get("/login/google")
async def login_with_google():
CLIENT_ID = "填写您的客户端 ID"
google_provider_cfg = requests.get("https://accounts.google.com/.well-known/openid-configuration").json()
authorization_endpoint = google_provider_cfg["authorization_endpoint"]
request_uri = (
authorization_endpoint
+ "?scope=openid%20email%20profile"
+ "&response_type=code"
+ "&client_id=" + CLIENT_ID
+ "&redirect_uri=http://localhost:3000/login/callback"
)
return {"url": request_uri}
@app.get("/login/callback")
async def login_callback(code: str = None):
CLIENT_ID = "填写您的客户端 ID"
CLIENT_SECRET = "填写您的客户端密钥"
token_endpoint = "https://oauth2.googleapis.com/token"
if code is None:
raise HTTPException(status_code=400, detail="Missing authorization code")
token_payload = {
"code": code,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"redirect_uri": "http://localhost:3000/login/callback",
"grant_type": "authorization_code"
}
token_response = requests.post(token_endpoint, data=token_payload)
id_token_jwt = token_response.json()["id_token"]
try:
idinfo = id_token.verify_oauth2_token(
id_token_jwt, requests.Request(), CLIENT_ID)
# 判断是否验证成功
if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
raise ValueError('Wrong issuer.')
userid = idinfo['sub']
# 将 userid 返回给前端,表示已登录成功
return {"userId": userid}
except ValueError:
# 验证失败,返回错误信息
raise HTTPException(status_code=401, detail="Unable to verify identity")
使用以下命令在本地启动 FastAPI 应用程序:
$ uvicorn main:app --reload
访问 http://localhost:8000/ 可以看到一个带有“使用 Google 账号登录”的链接的页面。
创建一个名为“frontend”的新文件夹,并使用以下命令在其中创建一个 ReactJS 应用程序。
$ npx create-react-app frontend
$ cd frontend
安装 Google APIs Client Library for JavaScript。
$ npm install google-auth-library
在“src”文件夹中创建一个名为“auth.js”的新 JavaScript 文件,并添加以下代码。
import { OAuth2Client } from "google-auth-library";
const client = new OAuth2Client("填写您的客户端 ID");
export const loginWithGoogle = async () => {
const { url } = await fetch("http://localhost:8000/login/google").then((response) => response.json());
window.location.href = url;
};
export const loginCallback = async (code) => {
const { userId } = await fetch(`http://localhost:8000/login/callback?code=${code}`).then((response) => response.json());
return userId;
};
export const verifyIdToken = async (idToken) => {
const ticket = await client.verifyIdToken({
idToken,
audience: "填写您的客户端 ID",
});
const { name, email, picture } = ticket.getPayload();
return { name, email, picture };
};
在“src”文件夹中的“App.js”文件中,添加以下代码。
import { useState, useEffect } from "react";
import { loginWithGoogle, loginCallback, verifyIdToken } from "./auth";
function App() {
const [userId, setUserId] = useState(null);
const [userProfile, setUserProfile] = useState(null);
useEffect(() => {
const query = new URLSearchParams(window.location.search);
const code = query.get("code");
if (code) {
loginCallback(code).then((userId) => {
setUserId(userId);
});
}
}, []);
useEffect(() => {
const fetchUserProfile = async () => {
const token = localStorage.getItem("accessToken");
if (!token) return;
const profile = await verifyIdToken(token);
setUserProfile(profile);
};
fetchUserProfile();
}, [userId]);
const handleLoginWithGoogle = () => {
loginWithGoogle();
};
const handleLogout = () => {
localStorage.removeItem("accessToken");
setUserId(null);
setUserProfile(null);
};
return (
<div className="App">
<header className="App-header">
<h1>Google 身份验证</h1>
{userId ? (
<>
<p>已登录</p>
<button onClick={handleLogout}>退出登录</button>
{userProfile && (
<div>
<img src={userProfile.picture} alt="" />
<p>{userProfile.name}</p>
<p>{userProfile.email}</p>
</div>
)}
</>
) : (
<button onClick={handleLoginWithGoogle}>使用 Google 账号登录</button>
)}
</header>
</div>
);
}
export default App;
使用以下命令启动 ReactJS 应用程序:
$ npm start
访问 http://localhost:3000/ 可以看到一个带有“使用 Google 账号登录”的按钮的页面。
在本文中,我们介绍了如何使用 FastAPI 和 ReactJS 实现服务器端的 Google 身份验证。该应用程序支持 Google 账号登录和退出登录,并能显示已登录用户的姓名、电子邮件地址和头像。在实际项目中,您可以根据需求进行定制化开发,以构建更复杂的应用。