1、drf-jwt手动签发与校验

2、drf小组件:过滤、筛选、排序、分页 => 针对与群查接口

jwt_token源码分析(入口)

rest_framework_jwt --> views.py --> ObtainJSONWebToken(JSONWebTokenAPIView)
class ObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer 然后到父类中JSONWebTokenAPIView的post方法
def post(self, request, *args, **kwargs):
#从get_serializer获取serializer
serializer = self.get_serializer(data=request.data)
........
点击get_serializer
def get_serializer(self, *args, **kwargs):
#获取到serializer_class类
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
回到
def post(self, request, *args, **kwargs):
# 这里就是将数据传入,然后反序列化做校验
serializer = self.get_serializer(data=request.data) if serializer.is_valid():
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
response_data = jwt_response_payload_handler(token, user, request)
response = Response(response_data)
if api_settings.JWT_AUTH_COOKIE:
expiration = (datetime.utcnow() +
api_settings.JWT_EXPIRATION_DELTA)
response.set_cookie(api_settings.JWT_AUTH_COOKIE,
token,
expires=expiration,
httponly=True)
return response return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 然后找到jwt的资源文件serializers.py中的JSONWebTokenSerializer(Serializer)
class JSONWebTokenSerializer(Serializer): def __init__(self, *args, **kwargs):
"""
Dynamically add the USERNAME_FIELD to self.fields.
"""
super(JSONWebTokenSerializer, self).__init__(*args, **kwargs)
#username_field是活的,而‘password’是死的
self.fields[self.username_field] = serializers.CharField()
#write_only=True说明只能是反序列化
self.fields['password'] = PasswordField(write_only=True)
点击PasswordField类
class PasswordField(serializers.CharField): def __init__(self, *args, **kwargs):
if 'style' not in kwargs:
kwargs['style'] = {'input_type': 'password'}
else:
kwargs['style']['input_type'] = 'password'
super(PasswordField, self).__init__(*args, **kwargs)
当我们发向接口发送post请求就要携带username和password字段,不然会报错,因为在反序列化的时候校验的只是这两个字段,所以说这两个字段是必填,然后返回token

value :记得加jwt空格+token

签发token源码分析

#通过账号密码签发token(依赖auth组件的RBAC用户权限六表)
class ObtainJSONWebToken(JSONWebTokenAPIView):
"""
API View that receives a POST with a user's username and password. Returns a JSON Web Token that can be used for authenticated requests.
"""
serializer_class = JSONWebTokenSerializer 点击JSONWebTokenAPIView,post方法是签发token
def post(self, request, *args, **kwargs):
#传入data进行反序列化校验
serializer = self.get_serializer(data=request.data)
#如果校验成功返回response
if serializer.is_valid():
#从序列化对象object是个字典,这个字典存放着user,token,就是这一步serializer = self.get_serializer(data=request.data)将数据给序列化类,这个类再通过username,password产生了用户并且产生了token,通过这个对象获取已经处理好的user和token #总结:获取user与签发token都是序列化类完成的 #获取用户
user = serializer.object.get('user') or request.user
#获取token
token = serializer.object.get('token')
#根据token,user,request封装成要被返回的数据
response_data = jwt_response_payload_handler(token, user, request)
#将数据做初始化得到response对象
response = Response(response_data)
if api_settings.JWT_AUTH_COOKIE:
expiration = (datetime.utcnow() +
api_settings.JWT_EXPIRATION_DELTA)
response.set_cookie(api_settings.JWT_AUTH_COOKIE,
token,
expires=expiration,
httponly=True)
#返回response对象
return response
#校验失败返回错误信息
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
查看序列化类资源文件serializers.py中的JSONWebTokenSerializer
class JSONWebTokenSerializer(Serializer):
"""
Serializer class used to validate a username and password. 'username' is identified by the custom UserModel.USERNAME_FIELD. Returns a JSON Web Token that can be used to authenticate later calls.
"""
def __init__(self, *args, **kwargs):
"""
Dynamically add the USERNAME_FIELD to self.fields.
"""
super(JSONWebTokenSerializer, self).__init__(*args, **kwargs) self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField(write_only=True) @property
def username_field(self):
return get_username_field()

想要进入到super中在is_valid()之前,也就是serializer这一步进行操作,不能下一步到is_valid()这一步进入就会没有数据,因为是再校验之前做的实例化

class JSONWebTokenSerializer(Serializer):

    def __init__(self, *args, **kwargs):
"""
Dynamically add the USERNAME_FIELD to self.fields.
"""
super(JSONWebTokenSerializer, self).__init__(*args, **kwargs) self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField(write_only=True) @property
def username_field(self):
return get_username_field() ##重点看这个校验函数方法
#全局钩子,就是post方法serializer.is_valid():做校验的时候就会走全局钩子校验
def validate(self, attrs):
#获取用户和密码
credentials = {
self.username_field: attrs.get(self.username_field),
'password': attrs.get('password')
} if all(credentials.values()):
#调用authenticate,就是将账号密码传入做认证,得到用户
user = authenticate(**credentials) if user:
#判断用户是否是活跃用户
if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg)
#根据用户产生payload对象,也就是用户的载荷,可以对外展示的信息,如用户的id,用户名,电话,过期时间等,但是没有密码,如果需要获取到用户的密码可以根据用户id来映射出用户密码
payload = jwt_payload_handler(user)
#返回有user和token的字典
return {
#传入payload产生签名
'token': jwt_encode_handler(payload),
'user': user
}
else:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg)
else:
msg = _('Must include "{username_field}" and "password".')
msg = msg.format(username_field=self.username_field)
raise serializers.ValidationError(msg)
   def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) if serializer.is_valid():
#校验通过就说明可以获取到用户和token,所以说user和token在全局钩子里已经产生了,在序列化类中就已经解析出user和password了,所以可以通过序列化对象获取到user和token
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
response_data = jwt_response_payload_handler(token, user, request)
response = Response(response_data)
if api_settings.JWT_AUTH_COOKIE:
expiration = (datetime.utcnow() +
api_settings.JWT_EXPIRATION_DELTA)
response.set_cookie(api_settings.JWT_AUTH_COOKIE,
token,
expires=expiration,
httponly=True)
return response return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

校验token源码分析

发送请求

urls.py
from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token
from django.urls import re_path
from api import views
urlpatterns = [
re_path(r'^jogin/$', obtain_jwt_token), re_path(r'^user/detail/$', views.UserDetail.as_view()), ]
views.py
from rest_framework.views import APIView
from utils.response import APIResponse
# 必须登录后才能访问 - 通过了认证权限组件
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class UserDetail(APIView):
#请求过来走JSONWebTokenAuthentication
authentication_classes = [JSONWebTokenAuthentication] # jwt-token校验request.user
#IsAuthenticated这个认证是判断request.user是否有值
permission_classes = [IsAuthenticated] # 结合权限组件筛选掉游客
def get(self, request, *args, **kwargs):
return APIResponse(results={'username': request.user.username})
走JSONWebTokenAuthentication,这个类没有authenticate认证方法,所以走父类BaseJSONWebTokenAuthentication
class BaseJSONWebTokenAuthentication(BaseAuthentication):
"""
Token based authentication using the JSON Web Token standard.
""" def authenticate(self, request):
"""
Returns a two-tuple of `User` and token if a valid signature has been
supplied using JWT-based authentication. Otherwise returns `None`.
"""
#传过来的authentication是带着请求头jwt,但是这里获取出来的没有带jwt
#没有认证,代表游客,返回none
jwt_value = self.get_jwt_value(request)
if jwt_value is None:
return None
#进行一通校验
try:
#通过token得到payload
payload = jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
#token过期捕获异常
msg = _('Signature has expired.')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
#如果校验失败就抛异常
raise exceptions.AuthenticationFailed()
#通过payload来获取用户,点击authenticate_credentials username = jwt_get_username_from_payload(payload)
#如果校验通过拿到user
user = self.authenticate_credentials(payload)
#返回user
return (user, jwt_value)

点击get_jwt_value

点击get_authorization_header()

想要获取到authenticate_credentials就可以views.py视图类中继承BaseJSONWebTokenAuthentication, authenticate_credentials是BaseJSONWebTokenAuthentication的方法

手动签发token

# 1)通过username、password得到user对象
# 2)通过user对象生成payload:jwt_payload_handler(user) => payload
# from rest_framework_jwt.serializers import jwt_payload_handler
# 3)通过payload签发token:jwt_encode_handler(payload) => token
# from rest_framework_jwt.serializers import jwt_encode_handler 签发token的请求 - 登录请求 - ObtainJSONWebToken - post - 将账号密码丢给序列化类处理 - 得到user、token => 序列化类的全局钩子

签发源码小总结:

# 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口

# 1)rest_framework_jwt.views.ObtainJSONWebToken 的 父类 JSONWebTokenAPIView 的 post 方法
# 接受有username、password的post请求
# 2)post方法将请求数据交给 rest_framework_jwt.serializer.JSONWebTokenSerializer 处理
# 完成数据的校验,会走序列化类的 全局钩子校验规则,校验得到登录用户并签发token存储在序列化对象中 自己的理解:
(只需要一条路由就可以签发token,视图类都不需要写)
携带json格式的用户密码超url发送post请求,url: obtain_jwt_token也就是ObtainJSONWebToken.as_view()方法 , ObtainJSONWebToken没有as_view(),到父类中JSONWebTokenAPIView中也没有,到JSONWebTokenAPIView的APIView中找到as_view并且返回调用view函数的返回值,view函数中dispatch方法,就是请求分发,所以post请求来到ObtainJSONWebToken没有,到父类JSONWebTokenAPIView找到,只写了这个post方法,所以get方法不行,serializer = self.get_serializer(data=request.data)调用ObtainJSONWebToken的对象调用get_serializer将data进去进行反序列化,get_serializer(data=request.data),get_serializer这个方法传入数据,是调用get_serializer中的 self.get_serializer_class()找到的serializer_class,serializer_class是在ObtainJSONWebToken中找到 serializer_class = JSONWebTokenSerializer,然后将JSONWebTokenSerializer(data=request.data)传入进行反序列操作,所以走JSONWebTokenSerializer的__init__方法,调用父类序列化,然后对传入的账号密码声明,校验走 validate方法,根据用户产生payload对象,也就是用户的载荷,可以对外展示的信息,如用户的id,用户名,电话,过期时间等,但是没有密码,如果需要获取到用户的密码可以根据用户id来映射出用户密码
payload = jwt_payload_handler(user)
#返回有user和token的字典
return {
#传入payload产生签名
'token': jwt_encode_handler(payload),
'user': user
}
核心源码:rest_framework_jwt.serializer.JSONWebTokenSerializer的validate(self, attrs)方法
def validate(self, attrs):
# 账号密码字典
credentials = {
self.username_field: attrs.get(self.username_field),
'password': attrs.get('password')
}
if all(credentials.values()):
# 签发token第1步:用账号密码得到user对象
user = authenticate(**credentials)
if user:
if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg)
# 签发token第2步:通过user得到payload,payload包含着用户信息与过期时间
payload = jwt_payload_handler(user)
# 在视图类中,可以通过 序列化对象.object.get('user'或者'token') 拿到user和token
return {
# 签发token第3步:通过payload签发出token
'token': jwt_encode_handler(payload),
'user': user
}
else:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg)
else:
msg = _('Must include "{username_field}" and "password".')
msg = msg.format(username_field=self.username_field)
raise serializers.ValidationError(msg)

手动校验token

# 1)从请求头中获取token
# 2)根据token解析出payload:jwt_decode_handler(token) => payloay
# from rest_framework_jwt.authentication import jwt_decode_handler
# 3)根据payload解析出user:self.authenticate_credentials(payload) => user
# 继承drf-jwt的BaseJSONWebTokenAuthentication,拿到父级的authenticate_credentials方法

校验源码小总结

# 前提:访问一个配置了jwt认证规则的视图类,就需要提交认证字符串token,在认证类中完成token的校验

# 1)rest_framework_jwt.authentication.JSONWebTokenAuthentication 的 父类 BaseJSONWebTokenAuthentication 的 authenticate 方法
# 请求头拿认证信息jwt-token => 通过反爬小规则确定有用的token => payload => user
核心源码:rest_framework_jwt.authentication.BaseJSONWebTokenAuthentication的authenticate(self, request)方法
def authenticate(self, request):
"""
Returns a two-tuple of `User` and token if a valid signature has been
supplied using JWT-based authentication. Otherwise returns `None`.
"""
# 带有反爬小规则的获取token:前台必须按 "jwt token字符串" 方式提交
# 校验user第1步:从请求头 HTTP_AUTHORIZATION 中拿token,并提取
jwt_value = self.get_jwt_value(request)
# 游客
if jwt_value is None:
return None
# 校验
try:
# 校验user第2步:token => payload
payload = jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
msg = _('Signature has expired.')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()
# 校验user第3步:token => payload
user = self.authenticate_credentials(payload) return (user, jwt_value)

代码详见:

E:\ten_django\page

jwt token认证的更多相关文章

  1. asp.net core 3.1 自定义中间件实现jwt token认证

    asp.net core 3.1 自定义中间件实现jwt token认证 话不多讲,也不知道咋讲!直接上代码 认证信息承载对象[user] /// <summary> /// 认证用户信息 ...

  2. Django JWT Token RestfulAPI用户认证

    一般情况下我们Django默认的用户系统是满足不了我们的需求的,那么我们会对他做一定的扩展 创建用户项目 python manage.py startapp users 添加项目apps INSTAL ...

  3. 程序员过关斩将--更加优雅的Token认证方式JWT

    菜菜,上次你讲的cookie和session认证方式,我这次面试果然遇到了 结果怎么样? 结果面试官问我还有没有更好的方式? 看来你又挂了 别说了,伤心呀.到底还有没有更好的方式呢? 你猜? 基于To ...

  4. JWT的优点和实现Token认证的安全问题

    JWT的优点和实现Token认证的安全问题 一.什么是JWT JWT——Json web token  是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,可实现无状态.分布式的Web应 ...

  5. token 与 基于JWT的Token认证

    支持跨域访问,无状态认证 token特点 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输 无状态(也称:服务端可扩展行): ...

  6. iOS 开发之基于JWT的Token认证机制及解析

    在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...

  7. 基于JWT的Token认证机制及安全问题

    [干货分享]基于JWT的Token认证机制及安全问题 https://bbs.huaweicloud.com/blogs/06607ea7b53211e7b8317ca23e93a891

  8. 二.3.token认证,jwt认证,前端框架

    一.token: 铺垫: 之前用的是通过最基本的用户名密码登录我的运维平台http://127.0.0.1:8000/---这种用的是form表单,但是这种对于前后端分离的不适合.前后端分离,应该通过 ...

  9. 使用jwt进行token认证

    简单说明:最近在搞权限这一块的东西,需要用到jwt进行token认证,才有了如下的demo演示   具体细节可以看gitbug,噗,不是bug是hub  github地址:https://github ...

随机推荐

  1. Python测试开发-创建模态框及保存数据

    Python测试开发-创建模态框及保存数据 原创: fin  测试开发社区  前天 什么是模态框? 模态框是指的在覆盖在父窗体上的子窗体.可用来做交互,我们经常会看到模态框用来登录.确定等等,到底是怎 ...

  2. Swizzling的使用

    在oc的runtime机制内有一类方法是可以用来实现类间的方法替换.解决了我们实际开发中诸多常规手段所无法解决的问题.关于Method Swizzling,这里有一篇介绍基本用法的文章 场景 最近出于 ...

  3. 如何正确的hook方法objc_msgSend · jmpews

    如何正确的hook方法objc_msgSend 前言 如果希望对 Objective-C 的方法调用进行 log, 一个很好的解决方法就是 hook 方法 objc_msgSend, 当然想到的就是利 ...

  4. pymongo bugfix后记

    有网友反馈py-mongo-sync同步异常,检查发现curosr[0]取查询结果第一个文档时报错"no such item for Cursor instance". 这里的逻辑 ...

  5. Quartz Tutorial 11 - Miscellaneous Features of Quartz

    文章目录 Plug-Ins Quartz提供了一个接口(org.quartz.spi.SchedulerPlugin) 用于插入附加的功能. 与Quartz一同发布的,提供了各种实用功能的插件可以在o ...

  6. 【快速上手】Git的使用教程

    创建Git仓库 git init 查看当前仓库情况 git status 添加修改 git add (file) or git add . 查看未提交的修改 git diff 撤销提交操作 git r ...

  7. SpringBoot快速上手系列01:入门

    1.环境准备 1.1.Maven安装配置 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件. 下载Maven可执行文件 cd /usr/local ...

  8. 软件工程实验一 Git代码版本管理

    实验一  GIT 代码版本管理 一.实验目的: 1)了解分布式分布式版本控制系统的核心机理: 2)熟练掌握git的基本指令和分支管理指令: 二.实验内容: 1)安装git: 2)初始配置git ,gi ...

  9. 使用EventBus + Redis发布订阅模式提升业务执行性能

    前言 最近一直奔波于面试,面了几家公司的研发.有让我受益颇多的面试经验,也有让我感觉浪费时间的面试经历~因为疫情原因,最近宅在家里也没事,就想着使用Redis配合事件总线去实现下具体的业务. 需求 一 ...

  10. UVA - 10462 Is There A Second Way Left?

    题意: 给你一张无向图,让你判断三种情况:1.不是连通图(无法形成生成树)2.只能生成唯一的生成树 3.能生成的生成树不唯一(有次小生成树),这种情况要求出次小生成树的边权值和. 思路: 比较常见的次 ...