JWT 登录与注销示例

1. 后端(Django + DRF)实现

安装依赖

首先,确保安装了 django-rest-frameworkdjango-rest-framework-simplejwt

pip install djangorestframework
pip install djangorestframework-simplejwt

配置 settings.py

# settings.py

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework_simplejwt.token_blacklist',  # 启用黑名单
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    ...
}

SIMPLE_JWT = {
    'AUTH_HEADER_TYPES': ('Bearer',),
}

创建视图(登录、注销)

# views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework import status

# 登录视图:获取 access 和 refresh token
class LoginView(APIView):
    def post(self, request):
        # 假设已经进行了用户名和密码的认证(这里只是示例,实际应用应使用用户验证逻辑)
        username = request.data.get('username')
        password = request.data.get('password')
        
        # 模拟用户名密码验证(实际应用中应使用 Django 的认证系统)
        if username == 'user' and password == 'password':
            refresh = RefreshToken.for_user(username)  # 为用户生成 refresh_token
            return Response({
                'access': str(refresh.access_token),  # 返回 access_token
                'refresh': str(refresh),  # 返回 refresh_token
            })
        return Response({"error": "Invalid credentials"}, status=status.HTTP_400_BAD_REQUEST)

# 注销视图:将 refresh_token 加入黑名单
class LogoutView(APIView):
    def post(self, request):
        refresh_token = request.data.get('refresh')
        try:
            token = RefreshToken(refresh_token)
            token.blacklist()  # 黑名单化该 refresh_token
            return Response(status=status.HTTP_205_RESET_CONTENT)
        except Exception as e:
            return Response({"error": "Invalid refresh token"}, status=status.HTTP_400_BAD_REQUEST)
#社交登录注销(social_django,是基于会话的)
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth import logout
from social_django.models import UserSocialAuth

class LogoutView(APIView):
    def post(self, request):
        # 注销当前用户
        logout(request)

        # 可选:删除社交平台的关联(如果需要)
        for social_auth in UserSocialAuth.objects.filter(user=request.user):
            social_auth.delete()

        return Response({"message": "Logged out successfully"})

配置路由(urls.py)

# urls.py

from django.urls import path
from .views import LoginView, LogoutView

urlpatterns = [
    path('api/login/', LoginView.as_view(), name='login'),
    path('api/logout/', LogoutView.as_view(), name='logout'),
]
from django.urls import path
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. 前端(Vue 3)实现

在前端,我们使用 axios 来处理 HTTP 请求,假设我们通过登录表单获取 usernamepassword,然后将 access_tokenrefresh_token 存储在 localStorage

安装 axios

npm install axios

登录函数

import axios from 'axios';

function login(username, password) {
  axios.post('http://localhost:8000/api/login/', { username, password })
    .then(response => {
      const { access, refresh } = response.data;
      // 存储 token
      localStorage.setItem('access_token', access);
      localStorage.setItem('refresh_token', refresh);

      // 设置默认的 Authorization header
      axios.defaults.headers.common['Authorization'] = `Bearer ${access}`;
      
      console.log('Login successful!');
    })
    .catch(error => {
      console.error('Login failed:', error.response.data);
    });
}

注销函数

function logout() {
  const refreshToken = localStorage.getItem('refresh_token');

  axios.post('http://localhost:8000/api/logout/', { refresh: refreshToken })
    .then(() => {
      // 清除 token
      localStorage.removeItem('access_token');
      localStorage.removeItem('refresh_token');

      // 清除 axios 默认 header
      delete axios.defaults.headers.common['Authorization'];

      console.log('Logout successful!');
    })
    .catch(error => {
      console.error('Logout failed:', error.response.data);
    });
}

3. 流程

  • 登录:前端通过提供用户名和密码请求 /api/login/,成功后获得 access_tokenrefresh_token,并将其存储在 localStorage 中。
  • 注销:前端请求 /api/logout/,将 refresh_token 发送到服务器,后端将该 refresh_token 加入黑名单,前端清除存储的 token。
  • 请求认证:前端的后续请求需要携带 access_token,后端通过 Authorization header 来验证用户身份。

4. 请求认证

在后续的 API 请求中,前端会将 access_token 放在请求头中以进行认证:

axios.get('http://localhost:8000/protected-endpoint/', {
  headers: {
    Authorization: `Bearer ${localStorage.getItem('access_token')}`
  }
})
.then(response => {
  console.log('Authenticated request:', response.data);
})
.catch(error => {
  console.error('Authentication failed:', error.response.data);
});

小结

  • 登录:用户通过用户名和密码请求 POST /api/login/,获取 access_tokenrefresh_token
  • 注销:用户请求 POST /api/logout/,将 refresh_token 加入黑名单,前端清除 token。
  • 请求认证:前端的后续请求需要携带 access_token,后端通过 Authorization header 来验证用户身份。
posted @ 2024-11-15 17:04  林汉州win  阅读(3)  评论(0编辑  收藏  举报