You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在已有的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:32:32