四、【Django】基于Jwt的token认证(登录接口)

简介

生成token, 就是把  某个东西  以某个key值(密钥)  加密 一下

简单的生成token举例

下面用python举例一下

# 安装
pip install pyjwt==1.7.1  (新版本的不行)

输入python,在python解析器里,运行生成token(要传payload参数,和key)

import jwt

paylod={"name":"taoker111"}

token =jwt.encode(payload=paylod,key="tk123")

# 解码 得到payload
# jwt.decode(token,key="123")

Django_rf的simplejwt

Django 3.1 版本之前是使用rest_framework_jwt 库,   之后版本的django会遇到这个报错

Could not import 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' for API setting 'DEFAULT_AUTHENTICATION_CLASSES'. ImportError: cannot import name 'smart_text' from 'django.utils.encoding'

djangorestframework-simplejwt 库提供了与 rest_framework_jwt 类似的 JSON Web Token (JWT) 认证功能。

1.安装

djangorestframework-simplejwt 库(如果尚未安装):

pip install djangorestframework-simplejwt

2.JWT 库默认的参数

 djangorestframework-simplejwt 默认使用一组默认值,但你可以根据需要设置这些参数。

如:

  •   默认token有效期为 5分钟
  •   生成token密钥SIGNING_KEY默认为 :setting.py 中, 创建项目就生成好了的一个 key值
  •  参数:AUTH_HEADER_TYPES 指定前缀,默认为Bearer

(from rest_framework_simplejwt.settings import )这么写然后点击settings

 如下是AUTH_HEADER_TYPES 前缀的意思,如果不配置,就是 Bearer开头

(后续可以登录成功后的access)使用pyjwt库来,用你的key来解码试试,它的信息包含这些

{'token_type': 'access', 'exp': 1689661573, 'iat': 1689661513, 'jti': 'eedea8e9d74b4da8b9e1932624952ee8', 'user_id': 3}

自定义配置JWT

 djangorestframework-simplejwt 默认使用一组安全的默认值,但你可以根据需要设置这些参数。例如,你可以在 settings.py 中添加以下配置:

# settings.py

from datetime import timedelta 
SIMPLE_JWT = {
    "AUTH_HEADER_TYPES": ("JWT",),          # 指定前缀
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),  # 访问令牌过期时间
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),  # 滑动刷新令牌的过期时间
    'SLIDING_TOKEN_REFRESH_LIFETIME_GRACE_PERIOD': timedelta(minutes=5),  # 滑动刷新令牌宽限期
    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',  # 滑动刷新令牌的过期时间声明名称
}

直接使用写登录

(不改默认的序列化器 和 视图)

自带了 登录视图类 TokenObtainPairView  对应的序列化器TokenObtainSlidingSerializer

(from rest_framework_simplejwt.views import)
(from rest_framework_simplejwt.serializers import)
这么写可以进入到源码

(它的序列化器默认用到的是JWT 里的这个配置 TOKEN_OBTAIN_SERIALIZER, 

 即rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer)

利用本身的TokenObtainPairView  和 TokenObtainSlidingSerializer实现登录

直接把它配置到urls中,就能使用登录

在外层urls.py中,配置

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),   # 用于获取
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),  # 用于更新
    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),     # 未知
    ...
]

获取token

使用POST请求,json格式传递 账号 和密码

自定义登录接口:

第一步:重写序列化器

即TokenObtainPairSerializer,原有的获取token序列化器要修改下

 from rest_framework_simplejwt.serializers import    这么写可以进入到源码)

token值中增加其他信息(不常用)

 做法:

在system应用下,或users 应用 中  serializers.py 中

class LoginSerializer(TokenObtainPairSerializer):
    """
    用户登录-序列化器(重写的)
    """
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)

        # Add custom claims
        token['name'] = user.username
        # ...

        return token

先去完成第二步 (如前面已经配置了url,直接配置 SIMPLE_JWT)

"TOKEN_OBTAIN_SERIALIZER": "system.serializers.LoginSerializer",

登录查看效果,然后使用JWT解析,密钥在setting.py中。

于是access信息(下图的token2)中,就多了name的信息:

修改响应结构、补充字段等

  • 序列化器:里面增加了user_info  用户信息( 这里的话,要配置setting,才生效)

如下是重写  获取token的序列化器 

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate

class LoginSerializer(TokenObtainPairSerializer):

    # 可修改一些提示语
    default_error_messages = {
        'no_active_account': ('该账号已被禁用,请与管理员联系!')
    }

    # 响应中,增加了user_info字段, 增加了token字段
    def validate(self, attrs):
        data = super().validate(attrs)

        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            "password": attrs["password"],

        }

        self.user = authenticate(**authenticate_kwargs)

        user = self.user
        # 获取用户信息
        user_info = {
            'id': user.id,
            'username': user.username,
            'email': user.email,
            # 添加其他用户信息...
        }

        # 补充一个token字段
        data["token"] = data["access"]

        # 将用户信息添加到响应数据中
        data['user_info'] = user_info
        return data

 松勤:

是把它当模型序列化器来用,指定了model, fields字段,

并且重写validate,即序列化器里提到的校验方法,并定义响应格式,成功或失败的

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
from system.models import User


class LoginSerializer(TokenObtainPairSerializer):
    class Meta:
        model = User
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {
        'no_active_account': ('该账号已被禁用,请与管理员联系!')
    }

    def validate(self, attrs):
        username = attrs['username']
        password = attrs['password']
        user = User.objects.filter(username=username).first()
        if not user:
            result = {
                "code": 400,
                "msg": "账号或密码不正确!",
                "data": None
            }
            return result

        if user and not user.is_staff:  # 判断是否允许登录后台
            result = {
                "code": 400,
                "msg": "您没有权限登录后台!",
                "data": None
            }
            return result

        if user and not user.is_active:
            result = {
                "code": 400,
                "msg": "该账号已被禁用,请与管理员联系!",
                "data": None
            }
            return result

        if user and user.check_password(password):  # check_password() 对明文进行加密,并验证
            data = super().validate(attrs)
            refresh = self.get_token(self.user)

            data['username'] = self.user.username
            data['userId'] = self.user.id
            data['refresh'] = str(refresh)  # refresh_token
            data['access'] = str(refresh.access_token)  # access_token
            request = self.context.get('request')
            request.user = self.user
            result = {
                "code": 200,
                "msg": "登录成功!",
                "data": data
            }
        else:
            result = {
                "code": 400,
                "msg": "账号或密码不正确!",
                "data": None
            }
        return result

 第二步:把重写的序列化器配置起来。

2. 视图类关联新定义的序列化器(假如已经在system应用下,serializers.py文件下重写好了)。

        方式1:配置(TokenObtainPairView 视图类自己会找到它)

SIMPLE_JWT = {
  # It will work instead of the default serializer(TokenObtainPairSerializer).
  "TOKEN_OBTAIN_SERIALIZER": "system.serializers.LoginSerializer",    # 应用.模块.类
  # ...    
}
   方式2(推荐这个,这样代码可读性高点):views重写登录视图类,并指定自己写的序列化器、  url中改成用新的视图类
from apps.system.serializers import  LoginSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
# 2.登录类
class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer

 url也配置在应用中(有更好的代码可读性)即可

认证方式设置为jwttoken认证

在 Django 的 settings.py 文件中进行设置认证方式中添加:JWTAuthentication:

# settings.py

REST_FRAMEWORK = {
      # a.在全局指定默认的认证类(指定认证方式)
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 先进行token认证(Django 3.1 版本不能用了)
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        # b.Session会话认证
        'rest_framework.authentication.SessionAuthentication',  # 次要进行session认证
        'rest_framework.authentication.BasicAuthentication'
    ],
    # 指定使用的权限类
    # a.在全局指定默认的权限类(当认证通过之后,可以获取何种权限)
    'DEFAULT_PERMISSION_CLASSES': [
        # AllowAny 不管是否有认证成功,都能获取所有权限
        # IsAdminUser 管理员(管理员需要登录)具备所有权限
        # IsAuthenticated 只要登录,就具备所有权限
        # IsAuthenticatedOrReadOnly,如果登录了就具备所有权限,不登录只具备读取数据的权限
        'rest_framework.permissions.AllowAny',
    ],
    # 其他设置...
}

假如不登录

 登录,获取到token

 

 其他接口中请求头中,传递Authorization,值默认为Bearer  +空格 +   登录返回的access值

官方文档地址是:Simple JWT — Simple JWT 5.2.2.post27+g47b7a08 documentation

  1. 安装和配置
  2. JWT 认证的使用方法和示例
  3. 设置 JWT 认证的参数和选项
  4. 刷新令牌和滑动刷新令牌的使用
  5. 撤销令牌的使用方法
  6. JWT 认证视图
  7. 自定义认证逻辑
  8. 常见问题解答
首先,需要安装 `djangorestframework` 和 `djangorestframework-jwt` 库: ``` pip install djangorestframework pip install djangorestframework-jwt ``` 然后在 Django 项目的 `settings.py` 文件中添加以下配置: ```python INSTALLED_APPS = [ # ... 'rest_framework', 'rest_framework.authtoken', 'rest_framework_jwt', # ... ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ), } JWT_AUTH = { 'JWT_SECRET_KEY': 'your-secret-key', 'JWT_ALGORITHM': 'HS256', 'JWT_ALLOW_REFRESH': True, 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), 'JWT_AUTH_HEADER_PREFIX': 'Bearer', } ``` 其中,`JWT_SECRET_KEY` 是一个随机字符串,用于加密生成 JWT token。 接下来,在 Django 项目的 `urls.py` 文件中添加以下代码: ```python from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_token urlpatterns = [ # ... path('api-token-auth/', obtain_jwt_token), path('api-token-refresh/', refresh_jwt_token), path('api-token-verify/', verify_jwt_token), # ... ] ``` 这里添加了三个路由,用于获取、刷新、验证 JWT token。 最后,为需要登录认证接口添加装饰器,例如: ```python from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @api_view(['GET']) @permission_classes([IsAuthenticated]) def my_view(request): content = {'message': 'Hello, World!'} return Response(content) ``` 这里使用了 `@permission_classes([IsAuthenticated])` 装饰器,表示只有通过 JWT token 认证的用户才能访问该接口。 至此,我们完成了 Django DRF 框架的 JWT 登录认证接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值