djangorestframework-simplejwt

0. 介绍

因为jwt官方已经停止维护,且对于django4.x不支持,所以选择simplejwt(django>=2.0)

一定要配合权限一起使用,不然不生效

1.使用

1.1 安装

先安装drf,因为jwt仅仅只是drf的一个第三方扩展且支持Django>=2.0

pip3 install djangorestframework-simplejwt -i https://pypi.douban.com/simple
pip3 install djangorestframework -i https://pypi.douban.com/simple

1.2 settings.py

# 修改配置
INSTALLED_APPS = [
'rest_framework',]

# 修改DRF认证
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',# 使用rest_framework_simplejwt(token)验证身份
        'rest_framework.authentication.SessionAuthentication',# 基于用户名密码认证方式
        'rest_framework.authentication.BasicAuthentication'  # 基于Session认证方式
    ],'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated'  # 默认权限为验证用户
    ],}
# 修改simplejwt
# simplejwt配置, 需要导入datetime模块
SIMPLE_JWT = {
    # token有效时长
    'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=30),# token刷新后的有效时间
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=1),}

1.3 urls.py

from django.contrib import admin
from django.urls import path,include

# 导入 simplejwt 提供的几个验证视图类
from rest_framework_simplejwt.views import (
    TokenObtainPairView,TokenRefreshView,TokenVerifyView
)

urlpatterns = [
    # Django 后台
    path('admin/',admin.site.urls),# DRF 提供的一系列身份认证的接口,用于在页面中认证身份,详情查阅DRF文档
    path('api/auth/',include('rest_framework.urls',namespace='rest_framework')),# 获取Token的接口
    path('api/token/',TokenObtainPairView.as_view(),name='token_obtain_pair'),# 刷新Token有效期的接口
    path('api/refresh/',TokenRefreshView.as_view(),name='token_refresh'),# 验证Token的有效性
    path('api/token/verify/',TokenVerifyView.as_view(),name='token_verify'),]

1.4 创建数据库并添加用户

python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser

1.5 访问路由

1.5.1 获取token

http://127.0.0.1/api/api/token/

 1.5.2 校验token

http://127.0.0.1/api/token/verify/

校验成功返回{} 

 1.5.2 刷新

http://127.0.0.1/api/refresh/

 1.6 key介绍

access:用于token失效时,刷新获得新的token

access:就是jwt里面的token

2. 报错AttributeError: 'str' object has no attribute 'decode' 

(135条消息) AttributeError: ‘str‘ object has no attribute ‘decode‘_骑台风走的博客-CSDN博客

from django.urls import path,re_path from .views import ArticleListAPIView,ArticleCreateAPIView,ArticleUpdateAPIView urlpatterns = [ # 图示展示(所有人) path('list/',ArticleListAPIView.as_view(),name='register'),]

3.1.2 view 


from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated

from .models import Article

from .serializers import ArticleListModelSerializer


class ArticleListAPIView(ListAPIView):
    """文章展示视图"""
    permission_classes = [IsAuthenticated]
    # select_related第一次拿数据时,就跨表拿到数据,防止多次查询
    queryset = Article.objects.filter(is_delete=False,is_show=True).select_related('userinfo')
    # print('queryset',queryset.first().__dict__)
    serializer_class = ArticleListModelSerializer

3.1.3 models

Article

from django.db import models

from users.models import UserInfo


class Article(models.Model):
    title = models.CharField(verbose_name='标题',max_length=225)
    desc = models.TextField(verbose_name="文章简介",null=True,blank=True)
    content = models.TextField(verbose_name="内容",blank=True)
    userinfo = models.ForeignKey(verbose_name='用户',to=UserInfo,on_delete=models.DO_NOTHING,blank=True,db_constraint=False)

    def __str__(self):
        return self.title

    class Meta:
        # 联合约束
        unique_together = ["title","userinfo"]
        # 联合索引
        index_together = ["title","content"]

UserInfo

需要在settings,py里面配置一下
# 注册自定义用户模型,格式:“app应用名.表名称”
AUTH_USER_MODEL = 'users.UserInfo'
from django.db import models
from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):
    """用户模型类"""
    phone = models.CharField(max_length=11,verbose_name='手机号码',unique=True)
    avatar = models.ImageField(upload_to='avatar',verbose_name='用户头像',blank=True)

    def __str__(self):
        return self.username

    class Meta:
        # 联合索引,联合同步查询,提高效率
        index_together = ["username","phone"]

3.1.4 serializer

from rest_framework import serializers

from . import models


class ArticleListModelSerializer(serializers.ModelSerializer):
    """
    文章展示序列化器
    """
    userinfo = serializers.SerializerMethodField()

    class Meta:
        model = models.Article
        fields = ['id','title','desc','content','userinfo']

    def get_userinfo(self,obj):
        """返回userinfo的username"""
        return obj.userinfo.username

3.2 认证

3.2.1 第一种方式

simplejwt的身份认证方式为:在请求的Headers里面里面添加设置参数,名称为:Authorization,值是一个固定组成的字符串: Bearer +空格 + access, 例如:Bearer [token值]。 正确的效果如下

 3.2.1 第二种

 4.Simple JWT的默认设置

# settings.py
 
from datetime import timedelta
 
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),# 访问令牌的有效时间
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),# 刷新令牌的有效时间
 
    'ROTATE_REFRESH_TOKENS': False,# 若为True,则刷新后新的refresh_token有更新的有效时间
    'BLACKLIST_AFTER_ROTATION': True,# 若为True,刷新后的token将添加到黑名单中,# When True,'rest_framework_simplejwt.token_blacklist',should add to INSTALLED_APPS
 
    'ALGORITHM': 'HS256',# 对称算法:HS256 HS384 HS512  非对称算法:RSA
    'SIGNING_KEY': SECRET_KEY,'VERIFYING_KEY': None,# if signing_key,verifying_key will be ignore.
    'AUDIENCE': None,'ISSUER': None,'AUTH_HEADER_TYPES': ('Bearer',),# Authorization: Bearer <token>
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',# if HTTP_X_ACCESS_TOKEN,X_ACCESS_TOKEN: Bearer <token>
    'USER_ID_FIELD': 'id',# 使用唯一不变的数据库字段,将包含在生成的令牌中以标识用户
    'USER_ID_CLAIM': 'user_id',# 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',# default: access
    # 'TOKEN_TYPE_CLAIM': 'token_type',# 用于存储令牌唯一标识符的声明名称 value:'access','sliding','refresh'
    #
    # 'JTI_CLAIM': 'jti',#
    # 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',# 滑动令牌是既包含到期声明又包含刷新到期声明的令牌
    # 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),# 只要滑动令牌的到期声明中的时间戳未通过,就可以用来证明身份验证
    # 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),# path('token|refresh',TokenObtainSlidingView.as_view())
}

 5.自定义

5.1自定义令牌+返回数据格式

如果你希望在payload部分提供更多信息,比如用户的username,这时你就要自定义令牌(token)了。

 5.1.1 seralizers.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer



class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    """
    自定义令牌
    """
    @classmethod
    def get_token(cls,user):
        token = super(MyTokenObtainPairSerializer,cls).get_token(user)

        # Add custom claims
        token['logo'] = '爱琉的缘'
        return token

    def validate(self,attrs):
        """
        自定义返回的格式
        """
        old_data = super().validate(attrs)

        # refresh = self.get_token(self.user)
        data = {'status': 1004,'msg': '成功',"token": old_data,# 'refresh': str(refresh),# 'access': str(refresh.access_token)
                }

        return data

5.1.2 views.py

from rest_framework_simplejwt.views import TokenObtainPairView                                                                         
from rest_framework.permissions import AllowAny

from .serializers import MyTokenObtainPairSerializer
 
 
 
 
class MyObtainTokenPairView(TokenObtainPairView):
    permission_classes = (AllowAny,)
    serializer_class = MyTokenObtainPairSerializer

5.1.3 urls.py

from django.urls import path,re_path,include
from rest_framework_simplejwt.views import (
    TokenObtainPairView,TokenVerifyView
)
from .views import MyObtainTokenPairView

urlpatterns = [
    # 刷新Token有效期的接口
    path('refresh/token/',# 验证Token的有效性
    path('check/token/verify/',]

5.2 自定义认证后台(Backend)

支持手机号/邮箱/账号+密码登录

5.2.1 authenticates.py

from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from django.contrib.auth import get_user_model

# 此方法将返回当前活动的用户模型
User = get_user_model()
# print(User)


class MyCustomBackend(ModelBackend):
    """自定义登录,支持用户名,手机,邮箱"""

    def authenticate(self,request,username=None,password=None,**kwargs):
        try:
            user = User.objects.get(Q(username=username) | Q(email=username) | Q(phone=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None

5.2.2 settings.py

# 支持多方式登录
AUTHENTICATION_BACKENDS = ['users.authenticates.MyCustomBackend']

6. jwt解码

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    """
    自定义令牌
    """

    

    def validate(self,attrs):
        """
        自定义返回的格式
        """

        from django.conf import settings

        from jwt import decode as jwt_decode
        refresh = self.get_token(self.user)
        # str(refresh.access_token) 就是token
        decoded_data = jwt_decode(str(refresh.access_token),settings.SECRET_KEY,algorithms=["HS256"])
        print(decoded_data) # {'token_type': 'access','exp': 1663135808,'jti': 'fd27374c6ac14d7b85d344979d812b6f','user_id': 1,'logo': '爱琉的缘'}
        return data

7. 手动颁发 token

    def _make_token(self,user):
        """手动签发token"""
        from rest_framework_simplejwt.tokens import RefreshToken
        refresh = RefreshToken.for_user(user)
        content = {
            'refresh': str(refresh),'access': str(refresh.access_token),}

8. 自定义token异常响应

middleware.py 中间件

class ExceptionChange:

    def __init__(self,get_response):
        self.get_response = get_response

    def __call__(self,request):
        response = self.get_response(request)
        return response

    def process_template_response(self,response):
        if hasattr(response,'data'):
            data = response.data
            # print(data)
            if isinstance(data,dict) is True:
                if "detail" in data.keys():
                    # 用户名或密码错误
                    if data.get("detail") == "No active account found with the given credentials":
                        del response.data["detail"]

                        response.data["code"] = 402
                        response.data["msg"] = "用户名或者密码错误!"

                    # 验证信息过期 token 过期
                    if data.get("detail") == "此令牌对任何类型的令牌无效":
                        del response.data["detail"]
                        del response.data["messages"]
                        response.data["code"] = 401
                        response.data["msg"] = "登录已过期,请重新登录"

                    # 未使用验证信息 未带验证信息请求
                    if data.get("detail") == "身份认证信息未提供。":  # 身份认证信息未提供。
                        del response.data["detail"]
                        response.data["code"] = 401
                        response.data["msg"] = "登录已过期,请重新登录"

                    # refresh 无效或者过期
                    if data.get("detail") == "令牌无效或已过期":  # 身份认证信息未提供。
                        del response.data["detail"]
                        response.data["code"] = 403
                        response.data["msg"] = "令牌无效或已过期"

        return response

在setting中配置


MIDDLEWARE = [
    ...
    'users.middleware.ExceptionChange',]

9. 权限

10. 认证

这是检测Django用户数据库的基本认证方案:

django: 配置为AUTHENTICATION_BACKENDS,

setting.py不写的话,AUTHENTICATION_BACKENDS默认设置为(‘django.contrib.auth.backends.ModelBackend’,),

2. 按照 AUTHENTICATION_BACKENDS 的排列顺序,如果同样的用户名和密码在第一次就匹配了,那么Django将停止处理后面的东西      

3. restful:  配置为 DEFAULT_AUTHENTICATION_CLASSES

11. 本文借鉴

(143条消息) djangorestframework-simplejwt入门教程_做我的code吧的博客-CSDN博客
(143条消息) Django REST Framework教程(7): 如何使用JWT认证(神文多图)_大江狗的博客-CSDN博客
djangorestframework-simplejwt简单使用 - 简书 (jianshu.com)(143条消息) DjangoRestFramework 使用 simpleJWT 登陆认证_PFFFei的博客-CSDN博客

原文地址:https://blog.csdn.net/qq_52385631

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有需要的朋友自行下载。
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。ViewSet在开发接口中不经常用。
一、Django介绍Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django 是一个开放源代码的 Web 应用框架,由 Python 写成。Django 遵守 BSD 版权,初次发布于 2005 年 7 月, 并于 2008 年 9 月发布了第一个正式版本 1.0 。Django学习线路Django 采用了 MVT 的软件设计模式,即模型(Model),视图(View)和模板(Template)。这个MVT模式并
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小白快速搭建django项目,并对可能出现的报错进行了分析
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的MysqlDB连接,Python3 支持支持pymysql 所有需要在app里面的__init__加上下面配置:
url: re_path(&#39;authors/$&#39;, views.AuthorView.as_view()), re_path(&#39;book/(?P\d+)/$&#39;, vie
前提 关于html寻找路线: template 如果在各个APP中存在, Django 会优先找全局template 文件下的html文件,如果全局下的template文件没有相关的html Djan
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
from bs4 import BeautifulSoup#kindeditordef kindeditor(request): s = &#39;&#39;&#39; &lt;li&gt;&lt;s
view.py 配置 html 配置
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault(&#39;content_type&#
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
return HttpResponse(&quot;OK&quot;) 返回一个字符串 return redirect(&quot;/index/&quot;) 返回URL return render
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault(&#39;content_type&#
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况
自动发送 &gt; 依赖jQuery文件 实例--&gt;GET请求: 手动发送 &gt; 依赖浏览器XML对象(也叫原生ajax) Ajax主要就是使用 【XmlHttpRequest】对象来完成请
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
return HttpResponse(&quot;OK&quot;) 返回一个字符串 return redirect(&quot;/index/&quot;) 返回URL return render