DRF之jwt使用说明书
jwt介绍
JsonWebToken
如何获取token
先创建一张用户表,要想使用jwt,必须使用django自带的用户表
-
在models.py中写一个用户类,导入、继承AbstractUser
-
在Terminal中做数据库迁移,createsuperuser创建超级用户
-
在路由中导入jwt的模块
# urls.py from django.urls import path, include,re_path from rest_framework_jwt.views import obtain_jwt_token from api import views urlpatterns = [ path('loginView/', views.Login.as_view()), re_path(r"^login/", obtain_jwt_token) # login触发jwt的视图函数 ]
-
向login发送post请求,请求体中加上username,password(这取决于用户表中的字段名),只需要且只能用这两个来认证
-
得到响应,响应中就是token
这里就得到了token,这个token有默认的过期时间,把它放在请求头可以用来做登陆认证
自定义认证
前端完成登陆,获取了token,放在请求头中发送给后端,后端接收并进行验证
如果使用jwt内置的认证方法,默认会把你header里token分开为两段,第一段是 JWT
第二段是token,jwt会拿第二段去认证
注:登录接口需要做 认证 + 权限 两个局部禁用
# auth.py
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework import exceptions
class MyToken(BaseJSONWebTokenAuthentication):
# 继承jwt的方法,重写authenticate
def authenticate(self, request):
jwt_value = str(request.META.get('HTTP_AUTHORIZATION'))
# 从请求头中取出token:http会自动把前端的authorization变成大写,加上HTTP_前缀
try:
payload = jwt_decode_handler(jwt_value)
# 使用继承的类中的方法取token中的payload,验证
print(payload)
except Exception:
raise exceptions.AuthenticationFailed("认证失败")
user = self.authenticate_credentials(payload)
return user, None
# 认证成功,返回用户对象,这时就可以在视图中任意位置取payload中给的信息了
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.auth import MyToken
class Login(APIView):
authentication_classes = [MyToken,]
# 局部使用,配置认证类。如果要全局使用,去setting中配置
def get(self,request):
return Response("Login")
使用内置的认证
内置的jwt前端使用格式是这样
访问需要登陆认证后才能访问的url时,在请求头(Header)中添加 Authorization:JWT <your_token> (Authorization 为 name,JWT <your_token> 为 value)
后端使用jwt内置的认证方式,仅需导入两个模块配置一下就可以了
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
# 认证模块
from rest_framework.permissions import IsAuthenticated
# 权限模块
from utils.auth import MyToken
class Login(APIView):
authentication_classes = [JSONWebTokenAuthentication,]
permission_classes = [IsAuthenticated]
# 配置认证和权限
def get(self,request):
return Response("Login")
注意,使用内置的认证方法,必须认证和权限一起使用才能有效,只使用一个认证不用权限,也可以访问到接口
控制返回的数据格式
控制登陆接口返回的数据格式,让obtain_jwt_token不止返回一个“token”,重写整个登陆接口,或使用原有的登陆接口,改一些配置
第一种方法,改配置
在jwt的配置文件中有个属性
'JWT_RESPONSE_PAYLOAD_HANDLER':'rest_framework_jwt.utils.jwt_response_payload_handler',
控制返回数据的格式,我们只要重写jwt_response_payload_handler的返回值,配置进去就可以控制返回的数据格式了
# setting.py 或者任意别的能先于jwt执行到的地方
from api.utils
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':'api.utils.my_jwt_response_payload_handler'
}
# utils.py
def my_jwt_response_payload_handler(token,user=None,request=None):
return {
'token':token,
'status':200,
'msg':'登陆成功'
}
自定义基于jwt的认证类
两种写法
# auth.py
# 第一种,基于BaseAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler # 跟上面是一个
import jwt
from api import models
class MyJwtAuthentication(BaseAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
# jwt提供了通过三段token,取出payload的方法,并且有校验功能
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('签名过期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('用户非法')
except Exception as e:
# 所有异常都会走到这
raise AuthenticationFailed(str(e))
# 因为payload就是用户信息的字典
print(payload)
# return payload, jwt_value
# 需要得到user对象,
# 第一种,去数据库查
# user=models.User.objects.get(pk=payload.get('user_id'))
# 第二种不查库
user=models.User(id=payload.get('user_id'),username=payload.get('username'))
return user,jwt_value
# 没有值,直接抛异常
raise AuthenticationFailed('您没有携带认证信息')
第二种
# 基于BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
#jwt提供了通过三段token,取出payload的方法,并且有校验功能
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('签名过期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('用户非法')
except Exception as e:
# 所有异常都会走到这
raise AuthenticationFailed(str(e))
user=self.authenticate_credentials(payload)
return user,jwt_value
# 没有值,直接抛异常
raise AuthenticationFailed('您没有携带认证信息')
在视图中使用authentication_classes = [MyJwtAuthentication,]
导入使用