我为什么要使用djangorestframework-simplejwt
image.png现在Django-rest-framework-jwt网上有许多文章
但是现在Django-rest-framework-jwt停止维护了
djangorestframework-simplejwt详细文档
安装
pip install djangorestframework_simplejwt
设置
在settings.py中
# 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
"""pine_mountain_bridge URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/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
from django.conf.urls import url, include
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
from django.views.static import serve
urlpatterns = [
path('admin/', admin.site.urls),
# rest_framework_simplejwt自带的得到token
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
# 刷新JWT
path('api/v1/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
# 验证token
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
得到token数据返回
refresh书用来刷新的
access是token
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4NjMxMjYyOSwianRpIjoiZWUzNTQxNmIzMDZjNDIyY2EyOWFiOGQ5NjhlNjc3ZWYiLCJ1c2VyX2lkIjoxfQ.th5AfYNsd9UK3zL9LEhnDRNrd37Ut8ucl-G9VzYlCHI",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNDI5LCJqdGkiOiJlYmI3ZDdmOTBlNzU0OTNkYjM4NTNiNTJkYzA0Yjk3NiIsInVzZXJfaWQiOjF9.WeoTxQ2rG0BOl9ji6KO3yfLm83kcsHV1drFDxGxAvGA",
}
刷新得到的数据
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
}
自定义djangorestframework-simplejwt
在你的serializers.py
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
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
PS 记得写url。我这里就不写了
得到token
{
"msg": "success",
"code": 1,
"data": {
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4NjMxMjYyOSwianRpIjoiZWUzNTQxNmIzMDZjNDIyY2EyOWFiOGQ5NjhlNjc3ZWYiLCJ1c2VyX2lkIjoxfQ.th5AfYNsd9UK3zL9LEhnDRNrd37Ut8ucl-G9VzYlCHI",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNDI5LCJqdGkiOiJlYmI3ZDdmOTBlNzU0OTNkYjM4NTNiNTJkYzA0Yjk3NiIsInVzZXJfaWQiOjF9.WeoTxQ2rG0BOl9ji6KO3yfLm83kcsHV1drFDxGxAvGA",
"username": "hahn",
"user_id": 1
}
}
刷新token
{
"msg": "success",
"code": 1,
"data": {
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg1NjIxNTIyLCJqdGkiOiI4MzcyN2UwYWVhMDU0MWYyYmE1ODljOWY5NTMzYjE2OSIsInVzZXJfaWQiOjF9.NTo1YKFl9tvcCYQVmBWLz0rhRL8044qT65jbe7okeG0"
}
}
接口验证
在你的views.py中
class UserViewSet(CacheResponseMixin, viewsets.ModelViewSet):
"""
测试的Api1
"""
permission_classes = [permissions.IsAuthenticated] # 权限认证主要是这个
queryset = User.objects.all()
serializer_class = UserSerializer
throttle_classes = []
# 自定义分页
pagination_class = LisPagination
错误返回
{
"msg": "身份认证信息未提供。",
"state": 0,
"data": ""
}
截屏2020-03-24上午10.35.52.png 截屏2020-03-24上午10.36.53.png这个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)
# 判断、写自己的业务逻辑
网友评论