如何在已有的Django登录页面中添加JWT认证
实现JWT认证在现有登录注册页面的应用
1. 调整登录页面的表单提交逻辑
把原来的同步表单提交改成异步请求,调用JWT的api/token接口获取令牌,示例代码如下:
<!-- 登录表单 --> <form id="login-form"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <button type="submit">登录</button> </form> <script> document.getElementById('login-form').addEventListener('submit', async function(e) { e.preventDefault(); const formData = new FormData(this); const response = await fetch('/api/token/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: formData.get('username'), password: formData.get('password'), }), }); if (response.ok) { const data = await response.json(); // 将令牌存入本地存储 localStorage.setItem('access_token', data.access); localStorage.setItem('refresh_token', data.refresh); // 跳转至需认证的页面 window.location.href = '/dashboard/'; } else { const error = await response.json(); alert(error.detail || '登录失败'); } }); </script>
确保后端已正确配置JWT路由:
# urls.py from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView urlpatterns = [ # 其他路由... path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), ]
2. 修改注册逻辑,实现注册后自动获取令牌
注册成功后直接为新用户生成JWT令牌并返回,前端拿到令牌后完成自动登录:
# views.py from django.contrib.auth.models import User from rest_framework.response import Response from rest_framework.decorators import api_view from rest_framework_simplejwt.tokens import RefreshToken @api_view(['POST']) def register(request): username = request.data.get('username') password = request.data.get('password') if User.objects.filter(username=username).exists(): return Response({'error': '用户名已存在'}, status=400) user = User.objects.create_user(username=username, password=password) # 生成JWT令牌 refresh = RefreshToken.for_user(user) return Response({ 'refresh': str(refresh), 'access': str(refresh.access_token), })
前端注册表单的异步提交逻辑:
<!-- 注册表单 --> <form id="register-form"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <button type="submit">注册</button> </form> <script> document.getElementById('register-form').addEventListener('submit', async function(e) { e.preventDefault(); const formData = new FormData(this); const response = await fetch('/api/register/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: formData.get('username'), password: formData.get('password'), }), }); if (response.ok) { const data = await response.json(); localStorage.setItem('access_token', data.access); localStorage.setItem('refresh_token', data.refresh); window.location.href = '/dashboard/'; } else { const error = await response.json(); alert(error.error || '注册失败'); } }); </script>
3. 保护需认证的页面/视图
对于需要登录才能访问的页面,后端需验证JWT令牌。如果是普通Django视图,可手动实现令牌验证:
# views.py from django.http import HttpResponseRedirect from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework.exceptions import AuthenticationFailed def dashboard(request): auth_header = request.headers.get('Authorization') if not auth_header or not auth_header.startswith('Bearer '): return HttpResponseRedirect('/login/') token = auth_header.split(' ')[1] try: jwt_auth = JWTAuthentication() validated_token = jwt_auth.get_validated_token(token) request.user = jwt_auth.get_user(validated_token) except AuthenticationFailed: return HttpResponseRedirect('/login/') return render(request, 'dashboard.html')
前端访问这类页面时,需在请求头中携带令牌,可封装通用请求函数处理令牌过期自动刷新:
async function fetchWithAuth(url, options = {}) { const accessToken = localStorage.getItem('access_token'); options.headers = { ...options.headers, 'Authorization': `Bearer ${accessToken}`, }; const response = await fetch(url, options); // 处理令牌过期情况 if (response.status === 401) { const refreshToken = localStorage.getItem('refresh_token'); const refreshResponse = await fetch('/api/token/refresh/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ refresh: refreshToken }), }); if (refreshResponse.ok) { const newTokens = await refreshResponse.json(); localStorage.setItem('access_token', newTokens.access); options.headers['Authorization'] = `Bearer ${newTokens.access}`; return fetch(url, options); } else { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login/'; } } return response; } // 调用示例 fetchWithAuth('/api/protected-data/') .then(res => res.json()) .then(data => console.log(data));
4. 实现退出登录功能
退出只需清除本地存储的令牌即可:
function logout() { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login/'; }
页面中添加退出按钮:
<button onclick="logout()">退出登录</button>
内容的提问来源于stack exchange,提问作者Aakrit bhargava
相关产品推荐
相关产品推荐

