Django REST Framework——8. JWT

Django REST Framework——8. JWT,第1张

Django REST Framework——8. JWT

文章目录
  • 一、Token与Session
    • 1. Session的弊端
    • 2. Token认证机制
  • 二、JWT的概念及构成
  • 三、Djangorestframework-simplejwt
    • 1. 安装与配置
    • 2. 基本使用方法
    • 3. 常用配置
    • 4. 自定义生成的Token内容
    • 5. JWT解码

一、Token与Session 1. Session的弊端

我们之前已经学过session,它是将用户的敏感信息保存到服务端,而只给客户端一个sessionid(保存为cookie)作为与服务器端session交互的凭证。在用户通过验证并拿到sessionid后,几乎每次访问都需要携带sessionid,并需要服务端每次都从数据库中获取session信息。这就暴露了如下的弊端:

  • 需要频繁查询数据库中的session,服务器压力大。

  • session是基于cookie的,如果cookie被截获,容易遭到CSRF攻击。

  • session被保存在用户第一次访问的服务器中(一般在内存中),如果有多个服务器,其他服务器无法获取到这些session信息,所以扩展性差。

2. Token认证机制
  1. 用户通过验证后,由服务端对数据进行编码;

  2. 将加密后的数据保存到客户端,称为Token:由js进行读写,保存在Local Storage中;

  3. 以后再访问服务端时,附带Token,服务端进行验证、解码。

如此,便减小了服务端的压力,由于不依赖于cookie,所以无需担心CSRF攻击。并且,Token由客户端发送,不依赖于某一台服务器,所以扩展性很好。

二、JWT的概念及构成

JWT的全称为JSON Web Token,它是一个开放的标准,定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。

JWT的本质就是一个字符串,它将用户信息保存到JSON字符串中,然后进行BSEA64编码,并附带一个签名(Signature),防止信息被篡改。

JWT看起来就是下面这样,因为是编码后的,所以是一堆乱七八糟的字符:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

它由三部分构成:

  1. Header(头部):通常包含token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)以及其他信息。

  2. Payload(载荷):是JWT的主体,通常包含用户主键、用户名、签发时客户信息(设备号、地址)、过期时间等。

    注意:因为base64是可逆的,所以不要在JWT的payload或header中放置敏感信息,除非它们是加密的!

  3. Signature(签名):是对上面两部分编码后的内容再进行加密后得到的密文。即:base64(Header)+"."+base64(Payload)通过SHA256加密后,得到的密文就是签名。

最后,将上面三部分通过.连接起来就得到了JWT。

三、Djangorestframework-simplejwt

Djangorestframework-simplejwt是DRF(django rest framework)的一个JWT认证插件,为DRF提供了一个JWT认证后端。

1. 安装与配置
  • 使用pip安装:

    pip install djangorestframework-simplejwt
    
  • 全局配置:

    在项目配置文件settings.py中,将JWTAuthentication添加到认证后端列表:

    REST_frameWORK = {
        ...
        'DEFAULT_AUTHENTICATION_CLASSES': (
            ...
            'rest_framework_simplejwt.authentication.JWTAuthentication',    
        )    
        ... 
    }
    
  • 局部配置:

    或者,仅在需要的视图中配置:

    class UserCenterView(GenericAPIView):
        authentication_classes = [JWTAuthentication]
        ……
    
  • 添加路由:

    from rest_framework_simplejwt.views import (   TokenObtainPairView, TokenRefreshView) 
    
    urlpatterns = [  
        # 获取token用的路由
        path('api/token/', TokenObtainPairView.as_view(),
             name='token_obtain_pair'),
        # 刷新token用的路由
        path('api/token/refresh/',  TokenRefreshView.as_view(), name='token_refresh')
    ]
    
  • 测试:

    创建django超级用户:

    python manage.py createsuperuser
    

    使用浏览器访问路径api/token/,会显示以下界面:

    输入用户名和密码点击POST后,验证通过就会返回token:

    说明:

    • access是token的主体;
    • refresh是用来刷新token的,执行token刷新 *** 作时,只会返回一个新的access。
2. 基本使用方法

在之前配置的基础上(此处默认为全局),向视图写入权限等其他配置:

class UserAPIView(GenericAPIView):
    """
    测试的Api1
    """
    # 全局设置了认证后端,不再进行局部设置
    # 设置权限认证,比如仅允许认证后的用户访问
    permission_classes = [permissions.IsAuthenticated] 
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
    def get(self, request):
        return Response("只有登录后的用户才能访问哦")

然后进行token的获取:

运行项目,使用POST方法请求路径api/token/,并在body中附带username和password信息。即可得到access。

最后使用GET方法访问UserAPIView视图,分为两种情况:

  • 错误情况:直接访问,没有附带Token,则会返回“身份认证信息未提供”的提示信息。
  • 正确情况:将token添加到请求头的Authorization中,就会成功返回“只有登录后的用户才能访问哦”。
3. 常用配置

可以在项目配置文件中,对jwt进行配置:

# Django project settings.py

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': settings.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',

    'JTI_CLAIM': 'jti',

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

    access token的有效时长,必须是一个datetime.timedelta对象。

  • REFRESH_TOKEN_LIFETIME:

    refresh token的有效时长,必须是一个datetime.timedelta对象。

  • ROTATE_REFRESH_TOKENS:

    刷新access token时,是否刷新refresh token。

  • UPDATE_LAST_LOGIN:

    当设置为True时,用户进行登录时,会在自动更新auth_user表的last_login字段。

  • ALGORITHM:

    生成签名部分的算法,可以使用’HS256’(默认), ‘HS384’, ‘HS512’。

  • AUTH_HEADER_NAME:

    用于身份验证的authorization头名称,默认为HTTP_AUTHORIZATION。

    比如获取authorization头的内容:

    class ExampleView(GenericAPIView):
        ...
        def get(self, request):
            token = request.meta.get("HTTP_AUTHORIZATION")
    
4. 自定义生成的Token内容

Djangorestframework-simplejwt也是通过序列化器来序列化和反序列化JWT的,所以我们可以通过自定义序列化器的方式,定制token。

在定义序列化器的文件中:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class MyTokenPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)

        # 添加自定义内容
        token['name'] = user.name
        ……

        return token

在视图文件中:

from rest_framework_simplejwt.views import TokenObtainPairView

from .serializers import *


class MyTokenObtainPairView(TokenObtainPairView):
    # 设置为自定义的token序列化器
    serializer_class = MyTokenObtainPairSerializer

最后,与标准token视图一样,配置好url即可。

注意:上面的修改会同时作用于获取Token和刷新Token *** 作

5. JWT解码

在定义序列化器的文件中:

from rest_framework_simplejwt.serializers import TokenVerifySerializer
from jwt import decode as jwt_decode

class MyTokenVerifySerializer(TokenVerifySerializer):

    def validate(self, attrs):
        """
        attrs['token']: 是请求的token
        settings.SECRET_KEY: setting.py默认的key 除非在配置文件中修改了
        algorithms: 加密的方法
        """
        decoded_data = jwt_decode(attrs['token'], settings.SECRET_KEY, algorithms=["HS256"])
        return decoded_data

在视图中:

from rest_framework_simplejwt.views import TokenObtainPairView, TokenViewbase
class MyTokenVerifyView(TokenViewbase):
    """
    验证token得到用户信息 token: 验证的token
    """
    serializer_class = MyTokenVerifySerializer

之后,访问该视图就会得到解码后的内容了。

当然,我们也可以通过python自带的base64库手动解码。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5690008.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存