如何基于React、Redux和Django自定义模型构建认证系统(不使用默认认证)
可行方案:基于React、Redux和Django自定义模型的认证系统
完全可以实现这个需求,下面分Django后端和React+Redux前端两部分给出具体实现步骤:
一、Django后端实现
1. 完善自定义用户模型
你的基础模型已经具备核心字段,补充密码加密和验证的方法,复用Django内置的安全哈希逻辑:
from django.db import models from django.contrib.auth.hashers import check_password, make_password class CustomUser(models.Model): username = models.CharField(max_length=150, unique=True) email = models.EmailField(unique=True) encrypted_password = models.CharField(max_length=255) # 设置加密密码 def set_password(self, raw_password): self.encrypted_password = make_password(raw_password) self.save() # 验证密码 def check_password(self, raw_password): return check_password(raw_password, self.encrypted_password)
2. 编写认证API视图
用Django REST Framework(DRF)实现注册、登录接口,结合JWT生成认证令牌(推荐用djangorestframework-simplejwt库):
from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from .models import CustomUser from rest_framework_simplejwt.tokens import RefreshToken # 用户注册接口 class RegisterView(APIView): def post(self, request): username = request.data.get('username') email = request.data.get('email') password = request.data.get('password') if CustomUser.objects.filter(email=email).exists(): return Response({'error': '邮箱已被注册'}, status=status.HTTP_400_BAD_REQUEST) user = CustomUser.objects.create(username=username, email=email) user.set_password(password) return Response({'message': '注册成功'}, status=status.HTTP_201_CREATED) # 用户登录接口 class LoginView(APIView): def post(self, request): email = request.data.get('email') password = request.data.get('password') try: user = CustomUser.objects.get(email=email) except CustomUser.DoesNotExist: return Response({'error': '账号或密码错误'}, status=status.HTTP_401_UNAUTHORIZED) if not user.check_password(password): return Response({'error': '账号或密码错误'}, status=status.HTTP_401_UNAUTHORIZED) # 生成JWT令牌 refresh = RefreshToken.for_user(user) return Response({ 'refresh': str(refresh), 'access': str(refresh.access_token), 'user': { 'username': user.username, 'email': user.email } }, status=status.HTTP_200_OK)
3. 配置路由与权限
在urls.py中注册API路由,并配置JWT认证保护需要权限的接口:
from django.urls import path from .views import RegisterView, LoginView from rest_framework_simplejwt.views import ( TokenRefreshView, ) urlpatterns = [ path('api/register/', RegisterView.as_view(), name='register'), path('api/login/', LoginView.as_view(), name='login'), path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # 其他需要认证的接口配置JWT认证类 ]
二、React+Redux前端实现
1. 配置Redux认证状态管理
用Redux Toolkit创建认证slice,处理登录、注册、登出的异步逻辑和状态:
// src/features/auth/authSlice.js import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from '../../utils/axios'; // 登录异步Action export const login = createAsyncThunk( 'auth/login', async (credentials, { rejectWithValue }) => { try { const res = await axios.post('/api/login/', credentials); // 持久化存储令牌和用户信息 localStorage.setItem('accessToken', res.data.access); localStorage.setItem('userInfo', JSON.stringify(res.data.user)); return res.data; } catch (err) { return rejectWithValue(err.response.data); } } ); // 注册异步Action export const register = createAsyncThunk( 'auth/register', async (userData, { rejectWithValue }) => { try { await axios.post('/api/register/', userData); return { message: '注册成功' }; } catch (err) { return rejectWithValue(err.response.data); } } ); // 初始化状态:从本地存储读取 const initialState = { user: JSON.parse(localStorage.getItem('userInfo')) || null, token: localStorage.getItem('accessToken') || null, loading: false, error: null }; const authSlice = createSlice({ name: 'auth', initialState, reducers: { logout: (state) => { state.user = null; state.token = null; localStorage.removeItem('accessToken'); localStorage.removeItem('userInfo'); } }, extraReducers: (builder) => { // 登录状态处理 builder .addCase(login.pending, (state) => { state.loading = true; state.error = null; }) .addCase(login.fulfilled, (state, action) => { state.loading = false; state.user = action.payload.user; state.token = action.payload.access; }) .addCase(login.rejected, (state, action) => { state.loading = false; state.error = action.payload.error; }) // 注册状态处理 .addCase(register.pending, (state) => { state.loading = true; state.error = null; }) .addCase(register.fulfilled, (state) => { state.loading = false; }) .addCase(register.rejected, (state, action) => { state.loading = false; state.error = action.payload.error; }); } }); export const { logout } = authSlice.actions; export default authSlice.reducer;
2. 配置Redux Store
将认证slice加入全局store:
// src/app/store.js import { configureStore } from '@reduxjs/toolkit'; import authReducer from '../features/auth/authSlice'; export const store = configureStore({ reducer: { auth: authReducer } });
3. 编写登录/注册组件
使用Redux的useDispatch和useSelector处理状态交互:
// src/components/Login.js import { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { login } from '../features/auth/authSlice'; const Login = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const dispatch = useDispatch(); const { loading, error } = useSelector(state => state.auth); const handleSubmit = (e) => { e.preventDefault(); dispatch(login({ email, password })); }; return ( <form onSubmit={handleSubmit} className="login-form"> <div className="form-group"> <label>邮箱</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> <div className="form-group"> <label>密码</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> {error && <p className="error-message">{error}</p>} <button type="submit" disabled={loading}> {loading ? '登录中...' : '登录'} </button> </form> ); }; export default Login;
4. 配置请求拦截器
自动为所有请求携带JWT令牌:
// src/utils/axios.js import axios from 'axios'; const axiosInstance = axios.create({ baseURL: 'http://localhost:8000' // 替换为你的Django API地址 }); // 请求拦截:添加Authorization头 axiosInstance.interceptors.request.use( (config) => { const token = localStorage.getItem('accessToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); export default axiosInstance;
5. 路由保护
创建高阶组件,拦截未登录用户访问受保护路由:
// src/components/ProtectedRoute.js import { Navigate } from 'react-router-dom'; import { useSelector } from 'react-redux'; const ProtectedRoute = ({ children }) => { const { user } = useSelector(state => state.auth); if (!user) { return <Navigate to="/login" replace />; } return children; }; export default ProtectedRoute;
关键注意事项
- Django端务必使用内置的密码哈希方法,不要自行实现加密逻辑,避免安全漏洞
- JWT令牌建议存储在
localStorage,但要注意XSS风险;若追求更高安全性,可改用HttpOnly Cookie(需后端配合配置) - Redux异步逻辑统一用
createAsyncThunk处理,避免回调嵌套 - 所有需要权限的Django API视图,需配置
permission_classes = [IsAuthenticated]和authentication_classes = [JWTAuthentication]
内容的提问来源于stack exchange,提问作者Mohammad Touhidul Islam
相关产品推荐
相关产品推荐

