7、DRF实战总结:JWT认证原理和使用及第三方库simplejwt 的详解(附源码)

在前面的DRF系列文章中,介绍了DRF认证(authentication)的本质, 以及自带的几种认证方案,包括TokenAuthentication方案。然而JSON Web Token(JWT)是一种更新的使用token进行身份认证的标准。与DRF内置的TokenAuthentication方案不同,JWT身份验证不需要使用数据库来验证令牌, 而且可以轻松设置token失效期或刷新token, 是API开发中当前最流行的跨域认证解决方案。

本文将详细介绍什么是JWT以及认证的工作原理,如何通过djangorestframework-simplejwt 这个第三方包轻松实现JWT认证,以及如何自定义令牌(token)和认证后台(backend)。

参考文章:

https://blog.csdn.net/zhouruifu2015/article/details/129965342icon-default.png?t=N2N8https://blog.csdn.net/zhouruifu2015/article/details/129965342

https://blog.csdn.net/zhouruifu2015/article/details/129965353icon-default.png?t=N2N8https://blog.csdn.net/zhouruifu2015/article/details/129965353

Json Web Token及其工作原理

JSON Web Token(JWT)是一种用于认证和授权的开放标准,允许在客户端和服务器之间传递信息,以验证用户身份和授权访问特定资源。它定义了一种紧凑且自包含的方式,用于各方之间安全地将信息以JSON对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。JWT用于为应用程序创建访问token,通常适用于API身份验证和服务器到服务器的授权。

JWT的优点包括:简单、轻量、可扩展、跨语言和跨平台使用。它也具有一定的安全性,因为JWT的签名只能由持有密钥的服务器生成和验证,且在传输过程中被中间人篡改可能会被检测出来。

紧凑和自包含这两个词的含义:

  1. 紧凑:就是说这个数据量比较少,可以通过url参数,http请求提交的数据以及http header多种方式来传递。
  2. 自包含:这个字符串可以包含很多信息,比如用户id,用户名,订单号id等,如果其他人拿到该信息,就可以拿到关键业务信息。

JWT认证工作原理

JWT的工作原理如下:

1. 用户登录系统并提供有效凭证,如用户名和密码(客户端提交用户登录信息验证身份)。

2. 服务器使用提供的凭证验证用户身份并生成JWT,生成的是一个用于证明用户身份的令牌(token),也就是一个加密后的长字符串。

3. 服务器将JWT传递给用户。

4. 用户在后续的请求中将JWT包含在HTTP请求头或请求体或url参数中,将这个令牌发送回服务器,服务器就知道请求来自哪个特定身份的用户了。

5. 服务器解码并验证JWT,以验证用户访问权限。

JSON Web Token由三部分组成,这些部分由点(.)分隔,分别是header(头部)payload(有效负载)signature(签名)

标头描述了JWT的类型和所使用的加密算法。常见的加密算法有HMAC SHA256和RSA。载荷包含了要传递的信息,如用户ID、角色、访问权限等。签名是将标头和载荷组合起来并使用密钥加密后的结果,用于验证JWT的完整性和真实性。

  1. header(头部): 识别以何种算法来生成签名;
  2. pyload(有效负载)用来存放实际需要传递的数据;
  3. signature(签名): 安全验证token有效性,防止数据被篡改。

通过http传输的数据实际上是加密后的JWT,它是由两个点分割的base64-URL长字符串组成,解密后可以得到header, payload和signature三部分。可以简单的使用 https://jwt.io/ 官网来生成或解析一个JWT,如下所示:

Django中使用JWT认证

使用djangorestframework-simplejwt这个第三方包进行JWT身份验证。

djangorestframework-simplejwt为Django REST框架提供了JSON Web令牌认证后端。它提供一组保守的默认功能来涵盖了JWT的最常见用例,还非常容易扩展。

安装依赖包:pip install djangorestframework-simplejwt

告诉DRF使用jwt认证作为后台认证方案。修改django_rest_framework_pro/settings.py

提供用户可以获取和刷新token的urls地址,这两个urls分别对应TokenObtainPairView和TokenRefreshView两个视图。

# 使用djangorestframework-simplejwt这个第三方包进行JWT身份验证
from django.contrib import admin
from django.urls import path, include
from reviews.views import ProductViewSet, ImageViewSet
from rest_framework.routers import DefaultRouter
from django.conf import settings
from django.conf.urls.static import static
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

router = DefaultRouter()
router.register(r'product', ProductViewSet, basename='Product')
router.register(r'image', ImageViewSet, basename='Image')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('', include(router.urls)),
]

if settings.DEBUG:
    urlpatterns += static(
        settings.MEDIA_URL,
        document_root=settings.MEDIA_ROOT
    )

使用postman测试,通过POST方法发送登录请求到/token/, 请求数据包括username和password。如果登录成功,将得到两个长字符串,一个是access token(访问令牌),还有一个是refresh token(刷新令牌),如下所示:

假如有一个受保护的视图(比如这里的/image/),权限(permission_classes)是IsAuthenticated,只有验证用户才可访问。访问这个保护视图时只需要在请求头的Authorization选项里输入刚才获取的access token即可,如下所示:

不过这个access token默认只有5分钟有效。5分钟过后,当再次访问保护视图时,将得到如下token已失效或过期的提示:

去获取新的access token,需要使用之前获得的refresh token。将这个refresh token放到请求的正文(body)里,发送POST请求到/token/refresh/即可获得刷新后的access token(访问令牌), 如下所示:

注意:Simple JWT中的access token默认有效期是5分钟,refresh token默认有效期是24小时。

更改Simple JWT的默认设置

Simple JWT的默认设置如下所示:

如果要覆盖Simple JWT的默认设置,可以修改settings.py, 如下所示。下例将refresh token的有效期改为了15天。

自定义令牌(token)

如果对Simple JWT返回的access token进行解码,会发现这个token的payload数据部分包括token类型,token失效时间,jti(一个类似随机字符串)和user_id。如果希望在payload部分提供更多信息,比如用户的username,这时就要自定义令牌(token)了。

编写reviews/serializers.py,添加如下代码。该序列化器继承了TokenObtainPairSerializer类。

其次,不使用Simple JWT提供的默认视图,使用自定义视图。修改myapp/views.py, 添加如下代码:

最后,修改django_simplejwt/urls.py, 添加如下代码,将/token/指向新的自定义的视图。注意:本例中的app名为reviews,所以是从reviews.views导入的MyObtainTokenPairView。

重新发送POST请求到/token/,将获得新的access token和refresh token,如下所示:

对重新获取的access token进行解码,将看到payload部分多了username的内容,在实际API开发过程中,通过Json Web Token传递更多数据非常有用。

扩展阅读

from rest_framework_simplejwt.serializers import (

    TokenObtainPairSerializer,

    TokenBlacklistSerializer,

    TokenRefreshSerializer,

    TokenVerifySerializer,

    TokenObtainSerializer,

    TokenObtainSlidingSerializer,

    TokenRefreshSlidingSerializer

)

1. TokenObtainPairSerializer: 用于生成访问(access)和刷新(refresh)令牌,当用户提供正确的用户名和密码时调用。

2. TokenBlacklistSerializer: 用于将访问和刷新令牌加入到令牌黑名单中,以便在用户注销、更改密码或帐户状态时使令牌失效。

3. TokenRefreshSerializer: 用于生成新的访问令牌,当用户使用有效的刷新令牌来刷新访问令牌时调用。

4. TokenVerifySerializer: 用于验证令牌的有效性,当需要验证访问令牌或刷新令牌时调用。

5. TokenObtainSerializer: 与TokenObtainPairSerializer类似,但不返回刷新令牌。

6. TokenObtainSlidingSerializer: 与TokenObtainPairSerializer类似,但允许配置访问令牌有效期。在有效期内,每次访问都会自动续期。

7. TokenRefreshSlidingSerializer: 与TokenRefreshSerializer类似,但允许配置访问令牌的有效期。在有效期内,每次刷新都会自动续期访问令牌。

自定义认证后台(Backend)

上面的示例是通过用户名和密码登录,通过自定义认证后台(Backend),同时支持邮箱/密码,手机/密码组合登录。

修改users/views.py, 添加如下代码:

其次,修改django_simplejwt/settings.py, 把自定义的验证方式添加到AUTHENTICATION_BACKENDS里去。

修改好后,使用postman发送邮箱/密码组合到/token/,将同样可以获得access token和refresh token。

源码地址:https://download.csdn.net/download/zhouruifu2015/87654240

输入才有输出,吸收才能吐纳。——码字不易

猜你喜欢

转载自blog.csdn.net/zhouruifu2015/article/details/129980628
今日推荐