如何在React JS中使用dj-rest-auth实现Google社交认证
基于dj-rest-auth的谷歌社交登录React实现方案
前置准备
- 确保Django后端的dj-rest-auth、social-auth-app-django配置完全无误,谷歌云控制台的OAuth同意屏幕、授权重定向URI已经修改为你的React应用地址,例如
http://localhost:3000/oauth/callback/google - React端推荐使用
@react-oauth/google库处理谷歌OAuth流程,安装命令:npm install @react-oauth/google - 注意:谷歌云控制台的授权重定向URI必须和你React应用的域名、端口完全匹配,否则会触发授权错误
核心环节:code/access_token获取实现
原Nuxt教程的本质是走谷歌OAuth2授权流程,React端逻辑完全一致,仅调用方式有差异,以下提供两种常用实现方案:
方案1:授权码模式(获取code,安全性更高,推荐)
该模式和原教程Nuxt端的授权逻辑完全对齐,首先在应用根组件包裹谷歌授权提供者:
import { GoogleOAuthProvider } from '@react-oauth/google'; function App() { return ( <GoogleOAuthProvider clientId="你在谷歌云控制台申请的客户端ID"> {/* 应用其余组件 */} <LoginPage /> </GoogleOAuthProvider> ); }
登录页组件代码示例:
import { useGoogleLogin } from '@react-oauth/google'; import axios from 'axios'; const LoginPage = () => { const googleLogin = useGoogleLogin({ flow: 'auth-code', // 指定走授权码模式,返回授权code onSuccess: async (codeResponse) => { // codeResponse.code即为所需的授权码 console.log('谷歌返回的授权码:', codeResponse.code); // 把code传给Django后端dj-rest-auth的谷歌登录接口 try { const res = await axios.post('你的Django服务地址/dj-rest-auth/google/', { code: codeResponse.code }); // 后端返回的JWT令牌存入本地存储或状态管理工具 localStorage.setItem('access_token', res.data.access); localStorage.setItem('refresh_token', res.data.refresh); } catch (err) { console.error('登录请求失败', err); } }, onError: (error) => console.log('谷歌授权失败', error) }); return ( <button onClick={() => googleLogin()}> 使用谷歌账号登录 </button> ); }; export default LoginPage;
方案2:隐式模式(直接获取access_token)
如果你的业务场景适合用隐式授权模式,仅需修改useGoogleLogin的配置参数即可:
const googleLogin = useGoogleLogin({ flow: 'implicit', // 指定隐式模式,直接返回谷歌侧的access_token onSuccess: async (tokenResponse) => { // tokenResponse.access_token即为所需的访问令牌 console.log('谷歌返回的access_token:', tokenResponse.access_token); // 传给后端接口的逻辑和方案1完全一致,仅请求参数替换为access_token const res = await axios.post('你的Django服务地址/dj-rest-auth/google/', { access_token: tokenResponse.access_token }); // 后续存令牌逻辑和方案1相同 } });
JWT令牌刷新实现
不需要依赖Nuxt的auth模块,React端可以通过封装axios拦截器实现自动刷新:
// 封装全局axios实例 import axios from 'axios'; const api = axios.create({ baseURL: '你的Django后端服务地址' }); // 请求拦截器:自动携带access_token api.interceptors.request.use((config) => { const token = localStorage.getItem('access_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 响应拦截器:access_token过期自动用refresh_token刷新 api.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; // 判定401状态且未重试过的请求自动刷新令牌 if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; const refreshToken = localStorage.getItem('refresh_token'); try { const res = await axios.post('你的Django服务地址/dj-rest-auth/token/refresh/', { refresh: refreshToken }); localStorage.setItem('access_token', res.data.access); // 重新发起原请求 return api(originalRequest); } catch (err) { // refresh_token也过期,清空本地存储跳转登录页 localStorage.clear(); window.location.href = '/login'; } } return Promise.reject(error); } ); export default api;
内容的提问来源于stack exchange,提问作者Jonathan Aplacador
相关产品推荐
相关产品推荐

