django-restframework-simplejwt使用
安装
pip install djangorestframework_simplejwt
设置
在settings.py中 ```python
drf配置
REST_FRAMEWORK = {
# JWT
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
JWT配置 里面具体配置可以参考文档
SIMPLE_JWT = { ‘ACCESS_TOKEN_LIFETIME’: timedelta(days=7), # 配置过期时间 ‘REFRESH_TOKEN_LIFETIME’: timedelta(days=15), }
> 在主目录下面的urls.py
> ```python
"""djangoProject15 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView)
urlpatterns = [
path('admin/', admin.site.urls),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
得到token数据返回
refresh书用来刷新的
access是token
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4ODk4MywianRpIjoiZWYyMDE1YzMwYzkwNGZlZjg0ZDNmM2ZiMmFiMDBmZDgiLCJ1c2VyX2lkIjozfQ.6fy8Dz6KDiBdTKBVAhjwi1jputZixD3yEJsFOY9JRFE",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA3MzgzLCJqdGkiOiI1ZDVhZTM5MTY2ZTk0NDYwYmFhYTRlODE5NTAyYmY1ZiIsInVzZXJfaWQiOjN9.seodK-XcsbgZ5AgwONxGzlDAFY3v5THQyiU-h7c-DE8"
}
刷新得到的数据
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
}
自定义djangorestframework-simplejwt
在你的serializers.py ```python from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
'''
token验证
'''
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data['refresh'] = str(refresh)
data['access'] = str(refresh.access_token)
data['username'] = self.user.username #这个是你的自定义返回的
data['user_id'] = self.user.id #这个是你的自定义返回的
return data
> 在你的views.py
> ```python
from rest_framework_simplejwt.views import TokenViewBase
from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from .serializers import *
from .models import *
class MyTokenObtainPairView(TokenObtainPairView):
"""
自定义得到token username: 账号或者密码 password: 密码或者验证码
"""
serializer_class = MyTokenObtainPairSerializer
class MyTokenRefreshView(TokenViewBase):
"""
自定义刷新token refresh: 刷新token的元素
"""
serializer_class = TokenRefreshSerializer
在你的url.py中ur
urlpatterns = [
"""
其他路由
"""
path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', MyTokenRefreshView.as_view(), name='token_refresh'),
]
得到token ```json
{ “refresh”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4OTQ0MiwianRpIjoiNGE4NjkwZDQ0MTVlNDBlNzkxMThhOGYzZTUyODdlYzAiLCJ1c2VyX2lkIjozfQ.DaCk2ADDDgof4l8goL4PZkDAVpGHcplYCry8mFI452M”, “access”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA3ODQyLCJqdGkiOiJkZjY2MGE3MWRmZmU0MGFlYjRkMzRmOTNjYzk0NThkNSIsInVzZXJfaWQiOjN9.boLQPtnnW10EVN2lUon6AG0N537E6Y5eadx5ttqnysg”, “username”: “admins”, “user_id”: 3 }
> 刷新token
> ```json
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMTQ4OTY2NiwianRpIjoiODgxNGE3M2YyNGY1NGM0ZGIyZjVlNGFiMGRiNmI2ZTIiLCJ1c2VyX2lkIjozfQ.LhlzCuxLdzwWq14V1Bu7pd19VZnIGCZHd1Cl3_6hNiI",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMDA4MDY2LCJqdGkiOiJlMzY2ZWJkOWVhYTA0NGI0YjZjMTk2N2RjM2U1MGRlOCIsInVzZXJfaWQiOjN9.VM2iMCB7GSi563np-kFdsgZ5337cLiHHE4p96n8G7dA",
"username": "admins",
"user_id": 3
}
接口验证
在你的views.py中 ```python class UserViewSet(CacheResponseMixin, viewsets.ModelViewSet): “”” 测试的Api1 “”” permission_classes = [permissions.IsAuthenticated] # 权限认证主要是这个 queryset = User.objects.all() serializer_class = UserSerializer throttle_classes = []
# 自定义分页
pagination_class = LisPagination
> 错误返回
> ```json
{
"msg": "身份认证信息未提供。",
"state": 0,
"data": ""
}
这个token是加在请求头的Authorization
太长就截图看了太长就截图看了
![]()
现在自定义token接口完成了
但是drf jwt默认验证的是username和password
突然想验证手机号码或者其他什么的只是自定义了
PS:本来想换请求数据中的key的、就是不要username、password。因为能力有限暂时不知道怎么换。看了好久源码好像是和Django user模型绑定了在settings.py中
pine_mountain_bridge里面的utils新建CustomToken.py
# 自定义JWT校验
AUTHENTICATION_BACKENDS = (
'pine_mountain_bridge.utils.CustomToken.CustomBackend',
)
CustomToken.py
# 自定义得到token校验
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from rest_framework import serializers
from users.models import *
class CustomBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
# print(request.data) 参考请求的其他数据
# print(request.data['demo']) 比如说key是demo的数据用来做你要的数据校验
try:
# 小编这里添加了一个手机验证,如果需要其他验证再加就ok了
try:
user = Users.objects.get(Q(username=username) | Q(mobile=username))
except Exception:
raise serializers.ValidationError({'': '账号没有注册'})
if user.check_password(password):
return user
else:
# 如果不想密码登录也可以验证码在这里写
# 这里做验证码的操作
raise serializers.ValidationError({'': '密码错误'})
except Exception as e:
raise e
返回数据
截屏2020-03-24上午10.45.40.png
jwt解码
根据token返回对于的数据
在你的serializers.py
from rest_framework_simplejwt.serializers import TokenVerifySerializer
from jwt import decode as jwt_decode
class MyTokenVerifySerializer(TokenVerifySerializer):
"""
token验证
"""
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
在views.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenViewBase
class MyTokenVerifyView(TokenViewBase):
"""
验证token得到用户信息 token: 验证的token
"""
serializer_class = MyTokenVerifySerializer
返回的数据
user_id就是你的用户ID
{
"msg": "success",
"status": 200,
"data": {
"token_type": "access",
"exp": 1585710741,
"jti": "97b42a6570d84108bf09701a60fbf5c1",
"user_id": 1
}
}
djangorestframework-simplejwt退出登录
JWT是不带退出内置的办法的
JWT退出登录很多方法
我这里是使用Django-redis库、用redis管理JWT的状态。用用户作为key保存token。
因为每个人的业务逻辑不一样、我就贴一些关键的代码在setting.py
# redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": "",
}
}
}
# redis缓存时间
REDIS_TIMEOUT = 60*60*24*7
使用
from django.core.cache import cache
保存redis缓存
# 设置redis缓存
# redis_key你的key
# token token
# REDIS_TIMEOUT 保存的数据
cache.set(redis_key, token, REDIS_TIMEOUT)
清除redis缓存
我这里是把value变成空了、方便我判断
# 设置redis缓存
# redis_key你的key
# REDIS_TIMEOUT 保存的数据
cache.set(redis_key,'', REDIS_TIMEOUT)
查看redis缓存
# 解码token得到user_id
decoded_data = jwt_decode(token algorithms=["HS256"])
# redis_key 你设置的redis的key
results = cache.get(redis_key)
# 判断、写自己的业务逻辑