django-rest-framework-jwt与django-rest-framework-simplejwt的对比及使用

目录

django-rest_framework_jwt

作者的信息

优势&劣势

使用

问题

django-rest-framework-simplejwt

作者信息

问题

权限分配


django-rest_framework_jwt(不推荐使用)

作者的信息

Github

作者在YouTube讲解Token结构

通过他的讲解,我们发现token分为三部分,以"."进行分割,使用Base64编码。

  • 第一部分我们称它为头部(header)
  • 第二部分我们称其为净负载(payload)
  • 第三部分是签名(signature)
作者讲解Header需要加参数

通过作者讲解可知道,添加验证后,需要在Header中添加参数Authorization,内容为 JWT <Token>。

使用文档

通过使用文档,我们可以简单的了解并进行基本配置。

使用视频

上面是b站的,没有字幕,油管上面有。

优势&劣势

JWT 的优势是服务端不再需要存储 Session,使得服务端认证鉴权业务可以方便扩展,避免存储 Session 所需要引入的 Redis 等组件,降低了系统架构复杂度。

JWT 的劣势是由于有效期存储在 Token 中,JWT Token 一旦签发,就会在有效期内一直可用,无法在服务端废止,当用户进行登出操作,只能依赖客户端删除掉本地存储的 JWT Token,如果需要禁用用户,单纯使用 JWT 就无法做到了。

使用

设置


REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',  # 使用JWT进行权限验证
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',  # 使用JWT进行授权
    ),
}
# JWT设置
JWT_AUTH = {
    # Token编码方法
    'JWT_ENCODE_HANDLER':
        'rest_framework_jwt.utils.jwt_encode_handler',
    # Token解码方法
    'JWT_DECODE_HANDLER':
        'rest_framework_jwt.utils.jwt_decode_handler',
    # payload添加
    'JWT_PAYLOAD_HANDLER':
        'rest_framework_jwt.utils.jwt_payload_handler',
    # 获取user_id
    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
        'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
    # 登录后payload返回
    'JWT_RESPONSE_PAYLOAD_HANDLER':
        'User_set.utils.JWTResponse.jwt_response_payload_handler',

    'JWT_SECRET_KEY': settings.SECRET_KEY,
    'JWT_GET_USER_SECRET_KEY': None,
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    # 算法
    'JWT_ALGORITHM': 'HS256',
    # 开启验证
    'JWT_VERIFY': True,
    # 开启验证过期时间
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    # 一天后Token过期
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,
    # 开启Token更新
    'JWT_ALLOW_REFRESH': True,
    # 一天后刷新的Token过期
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
    # 默认Token前缀
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
    'JWT_AUTH_COOKIE': None,
}

自定义登录后的返回(添加前端可能需要的信息)

def jwt_response_payload_handler(token, user=None, request=None):
    """为返回的结果添加用户相关信息"""

    return {
        'token': token,
        'user_id': user.id,
        'username': user.username
    }

 未登录前查看api,会发现验证不通过。

未登录无法查看api

登录并得到token

登录并得到token

调试方法1:curl

curl安装与使用

curl下载地址

下载.zip文件后解压,进行配置,博主是在Windows系统下编程的,配置如下。

标题


 

标题
标题

安装成功后,按照curl语法进行测试就好。

使用curl进行调试

调试方法2:postman

Windows下,不想敲命令的话,可以使用postman,Headers参数里面添加上Authorization参数即可。

使用postman调试

问题

有两个过期时间,一个是Token的过期时间(JWT_EXPIRATION_DELTA),应该很短,我们应该经常更新Token来保证安全。一个是刷新过期时间(JWT_REFRESH_EXPIRATION_DELTA),用户需要保存密码,自动登录的时间,在此期间如果Token过期了,应该自动进行Refresh。然而,作者把刷新的View写成了如果Token没有过期,那么可以进行刷新??? What???那还有啥用。

问题348

目前,作者在notice中写不再更新了,而这个基本问题都没有解决。

提供一个思路:我们把Token存起来,在更新时,如果已经过期,但是和保存的一样,那么进行更新。

AUTH_USER_MODEL 配置时出了问题,显示路径不对,应该只是包名加类名。例如,auth.User。下面是stack overflow的回答,表示感谢。

stack overflow

django-rest-framework-simplejwt

作者信息

Github

他解决上面的问题,使用了access作为Token,一旦它过期,但是刷新时间还没有过期,那么可以使用refresh进行更新,得到新的access和refresh。

登录成功获得access和refresh

Header中,Authorition的前缀不再是JWT 而是Bearer。

问题

他使用了TokenUser作为鉴权用户,直接在代码里面写死了,问题是is_superuser和is_staff都是false,username还是默认为空。那么登录后,我们获取的request.user的类型就是TokenUser类。在Group.objects.filter(user=request.user)时,就会报错。

解决思路:在使用Group等需要参数request.user时,将request.user(TokenUser类型)转为django.concrib.auth.models.user。我们可以通过user=User.objects.get(id=request.user.id)来进行转换。

另外,在Issues下,有人提供了思路,在设置中添加TOKEN_USER_CLASS来让开发者替换TokenUser,但是作者没有merge,用pip install去下载时并没有这段代码,你可以把这段代码下载下来,作为app放到自己的项目里面。

权限分配

权限分配和验证差不多,具有全局配置,和类的配置,如果你使用方法作为视图的话,可以使用@api_view()方法。在REST官方文档中,没有给出如何对类的某个方法进行权限认证。

阅读源代码,可以发现在APIView里面利用get_permissions方法对permission_classes进行遍历并实例化,对类的某个方法进行权限分配就需要重写get_permissions方法。

# 测试对类的方法进行权限分配
class TestView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = UserInfoSerializer
    queryset = User.objects.all()

    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        permission_classes = []
        if self.request.method == 'GET':
            permission_classes.append(GetPermission)
        if self.request.method == 'PUT':
            permission_classes.append(PutPermission)
        return [permission() for permission in self.permission_classes]

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

发布了163 篇原创文章 · 获赞 471 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/lady_killer9/article/details/103075076
今日推荐