Django Rest Framework 和 JWT 身份验证

为了方便解决跨域身份验证问题,本章我们在之前的项目中集成 Django Rest Framework 和 JWT 身份验证。

1. 集成 Django Rest Framework

1.1 安装

pip install djangorestframework

pip install pyjwt

然后在 settings.py的INSTALLED_APPS中添加rest_framework。

1.2 Class-Based Views

python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response

class SnippetDetail(APIView):
    def get(self, request):  # 查找
        ...
        return Response(...)

    def post(self, request):  # 创建
        ...
        return Response(...)

    def put(self, request, pk):  # 修改
        ...
        return Response(...)

    def delete(self, request, pk):  # 删除
        ...
        return Response(...)

2. 集成JWT验证

2.1 安装

pip install djangorestframework-simplejwt

然后在settings.py中添加:

python 复制代码
INSTALLED_APPS = [
    ...
    'rest_framework_simplejwt',
    ...
]

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}

2.2 配置

在settings.py中添加:

python 复制代码
from datetime import timedelta
...

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': False,
    'BLACKLIST_AFTER_ROTATION': False,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

2.3 添加获取jwt和刷新jwt的路由

python 复制代码
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.4 手动获取jwt

python 复制代码
from rest_framework_simplejwt.tokens import RefreshToken

def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)

    return {
        'refresh': str(refresh),
        'access': str(refresh.access_token),
    }

2.5 将jwt验证集成到Django Channels中

创建文件channelsmiddleware.py

python 复制代码
"""General web socket middlewares
"""

from channels.db import database_sync_to_async
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.tokens import UntypedToken
from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication
from channels.middleware import BaseMiddleware
from channels.auth import AuthMiddlewareStack
from django.db import close_old_connections
from urllib.parse import parse_qs
from jwt import decode as jwt_decode
from django.conf import settings
@database_sync_to_async
def get_user(validated_token):
    try:
        user = get_user_model().objects.get(id=validated_token["user_id"])
        # return get_user_model().objects.get(id=toke_id)
        return user

    except:
        return AnonymousUser()

class JwtAuthMiddleware(BaseMiddleware):
    def __init__(self, inner):
        self.inner = inner

    async def __call__(self, scope, receive, send):
       # Close old database connections to prevent usage of timed out connections
        close_old_connections()

        # Try to authenticate the user
        try:
            # Get the token
            token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]

            # This will automatically validate the token and raise an error if token is invalid
            UntypedToken(token)
        except:
            # Token is invalid

            scope["user"] = AnonymousUser()
        else:
            #  Then token is valid, decode it
            decoded_data = jwt_decode(token, settings.SIMPLE_JWT["SIGNING_KEY"], algorithms=["HS256"])

            # Get the user using ID
            scope["user"] = await get_user(validated_token=decoded_data)
        return await super().__call__(scope, receive, send)


def JwtAuthMiddlewareStack(inner):
    return JwtAuthMiddleware(AuthMiddlewareStack(inner))

3. 配置Nginx

打开/etc/nginx/nginx.conf,在location /的路由中添加对PUT、POST、DELETE方法的支持。完整配置见【创建应用】界面。

bash 复制代码
if ($request_method = 'POST') {
    add_header 'Access-Control-Allow-Origin' 'https://www.acwing.com';
    add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'DELETE') {
    add_header 'Access-Control-Allow-Origin' 'https://www.acwing.com';
    add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}

修改完后,执行:sudo nginx -s reload,使修改生效。

相关推荐
Java编程爱好者12 分钟前
Seata实现分布式事务:大白话全剖析(核心讲透AT模式)
后端
神奇小汤圆14 分钟前
比MySQL快800倍的数据库:ClickHouse的性能秘密
后端
aiguangyuan37 分钟前
使用LSTM进行情感分类:原理与实现剖析
人工智能·python·nlp
小小张说故事1 小时前
BeautifulSoup:Python网页解析的优雅利器
后端·爬虫·python
怒放吧德德1 小时前
后端 Mock 实战:Spring Boot 3 实现入站 & 出站接口模拟
java·后端·设计
luoluoal1 小时前
基于python的医疗领域用户问答的意图识别算法研究(源码+文档)
python
Shi_haoliu1 小时前
python安装操作流程-FastAPI + PostgreSQL简单流程
python·postgresql·fastapi
biyezuopinvip1 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
UrbanJazzerati1 小时前
Python编程基础:类(class)和构造函数
后端·面试
ZH15455891311 小时前
Flutter for OpenHarmony Python学习助手实战:API接口开发的实现
python·学习·flutter