drf-jwt
jwt
一 jwt基本认知
为什么要用jwt?
避免了大量io,所以大大降低数据库的压力以及后端的压力
见图:
安装drf-jwt
具体token串(了解)
"""
jwt:json web tokens 采用json格式在web上传输的 认证字符串
jwt字符串:头.载荷.签名
头:公司基本信息、项目组基本信息、常规加密算法名
载荷:用户信息、过期时间
签名:头、载荷、秘钥
{头信息字典,采用base64加密算法}.{载荷信息字典,采用base64加密算法}.{头加密串、载荷加密串、服务器秘钥,采用hs256加密算法}
base64是可逆加密
hash256是不可逆加密
"""
加密解密没啥好说的,但是如果hash成功了第三段的话,那么也就意味着这个加密串是我发的,因为用的hash算法是同一个,那么服务器也是统一个。
# 大概思路
#1 首先制作token
把第一段和第二段base64加密出来,然后把第一段和第二段加密成了第三段。
#2 验证token
首先拿着第一段和第二段hash一下,看看是否是第三段,然后base64解密第一段。
二 具体使用
urls.py
from django.conf.urls import url,include
from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token
from . import views
urlpatterns = [
# 1 直接可以post访问得到 token
# 自带post方法 会自己校验 username以及password 并且设置好token进行返回
url(r'^v2/login/$', obtain_jwt_token),
# 2 利用源码定制token进行返回
url(r'^v3/login/$', views.LoginJWTAPIView.as_view()),
# 3 认证组件的使用
url(r'^v3/cars/$', views.CarV3ModelViewSet.as_view({
'get': 'list',
'post': 'create'
})),
url(r'^v3/cars/(?P<pk>.*)/$', views.CarV3ModelViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
})),
]
views.py
from django.shortcuts import render
# Create your views here.
#### authors 组件小用法跟本文不大
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib import auth
class LoginSessionAPIView(APIView):
# 登录要禁用认证与权限
authentication_classes = []
permission_classes = []
def post(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
if not (username and password):
return Response('信息有误')
# user = models.User.objects.filter(username=username).first() # type: models.User
# user.check_password(password)
# 直接自己就可以进行验证了
user = auth.authenticate(request, username=username, password=password)
if not user:
return Response('登录失败')
auth.login(request, user=user) #会把sessionid放进去返回
return Response('登录成功')
# 直接drf的源码的封装token和解密token的部件使用
from . import models
import re
from my_utils.response import APIResponse
from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler
class LoginJWTAPIView(APIView):
authentication_classes = ()
permission_classes = ()
def post(self, request, *args, **kwargs):
# username可能携带的不止是用户名,可能还是用户的其它唯一标识 手机号 邮箱
username = request.data.get('username')
password = request.data.get('password')
# 如果username匹配上手机号正则 => 可能是手机登录
if re.match(r'1[3-9][0-9]{9}', username):
try:
# 手动通过 user 签发 jwt-token
user = models.User.objects.get(mobile=username)
except:
return APIResponse(1, '该手机未注册')
# 邮箱登录 等
# 账号登录
else:
try:
# 手动通过 user 签发 jwt-token
user = models.User.objects.get(username=username)
except:
return APIResponse(1, '该账号未注册')
# 获得用户后,校验密码并签发token
# 这个验证密码感觉是自带的 会把你的密码和数据库的密码进行对比
# python的Django框架自带了一套加密方法: make_password(), 具体作用如下:
# 这时候如果需要验证密码比较是否正确就需要用check_password( ),具体如下:
if not user.check_password(password):
return APIResponse(1, '密码错误')
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return APIResponse(0, 'ok', results={
'username': user.username,
'mobile': user.mobile,
'token': token
})
# 局部使用jwt认证组件
from . import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class CarV3ModelViewSet(ModelViewSet):
# 认证组件的token格式是 在Headers里添加字段 authorization:jwt sdfj.jasdf.xxyandls
authentication_classes = [JSONWebTokenAuthentication] # 用token确定身份 游客 or 登录用户 用request.user来确定
permission_classes = [IsAuthenticatedOrReadOnly] # 根据身份确定权限
queryset = models.Car.objects.filter(is_delete=False)
serializer_class = serializers.CarModelSerializer
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
obj.is_delete = True
obj.save()
return Response('删除成功')
setting.py
# 配置自定义User表
AUTH_USER_MODEL = 'api.user'
# 配置自定义User表
AUTH_USER_MODEL = 'api.user'
# jwt配置
import datetime
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=30000),
'JWT_AUTH_HEADER_PREFIX': 'TOKEN', # 可以修改访问的时候具体修改 'jwt' 的内容
}
serializers.py
from rest_framework import serializers
from . import models
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('username', 'mobile')
class CarModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Car
fields = ('name',)