Simple JWT
目录
Simple JWT
安装
pip install djangorestframework_simplejwt
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication', # 必须配置的认证类
],
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
# 当你在验证token的时候是需要配置一个权限类的,IsAuthenticated是drf自带的,在这里全局配置之后那么你的所有的视图就不必一个个配置权限类了
}
注意
所有的用户验证所使用的表是django自带的user表
简单实现生成token及验证
urls.py
from rest_framework_simplejwt.views import (
TokenObtainPairView, # 双token
TokenRefreshView,
TokenObtainSlidingView, # 下面两个是单token,用法一样
TokenRefreshSlidingView
)
urlpatterns = [
path('test-auto-token', TokenObtainPairView.as_view()),
path('refresh', TokenRefreshView.as_view()),
]
获取token
默认是使用username和password去登陆返回token
刷新token
自定义使用email或者phone登陆
backend.py
from django.contrib.auth.backends import ModelBackend
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(email=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
setting.py
# 自定义JWT校验
AUTHENTICATION_BACKENDS = (
'app01.backend.CustomBackend',
)
定制化payload和token(双token)
views.py
from rest_framework_simplejwt.views import TokenObtainPairView
class TestJwtToken(TokenObtainPairView):
serializer_class = MyTokenObtainSerializer
serializers.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username # 这里的username会加入到payload里
return 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['email'] = self.user.email # 这里会在接口里返回email字段,看下图
return data
在get_token方法里加字段是在token的payload里去添加数据,在使用base64解码的时候会显示出你添加的字段
b'{"typ":"JWT","alg":"HS256"}{"token_type":"refresh","exp":1669017564,"jti":"86a53bd885374f1ca8715e1e3f302a3e","user_id":2,"username":"admin"}
# 在这里username就被添加进了payload里了
在validate方法里的data字典加字段,就是在返回token的response里加数据
自定义生成token(可塑性高)
双token
from rest_framework_simplejwt.tokens import RefreshToken
class MyReturnToken(APIView):
def get(self, request, *args, **kwargs):
user = Client.objects.get(pk=1)
refresh = RefreshToken.for_user(user) # 只要传user对象就行了
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token)
})
单token
from rest_framework_simplejwt.tokens import SlidingToken
class MyReturnToken(APIView):
def get(self, request, *args, **kwargs):
user = Client.objects.get(pk=2)
# refresh = RefreshToken.for_user(user)
token = SlidingToken.for_user(user)
print(token)
print(type(token))
return Response(data=str(token))
认证和权限特点
在drf中,认证、权限、频率有一个共性,使用顺序是
- 视图配置>settings文件配置>def配置文件配置
- 当视图配置了,那就不会使用settings文件配置的了
drf配置文件内默认的认证类和权限类
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
当你是使用simple jwt去认证的时候,全局加的JWTAuthentication认证会返回一个user对象,然后全局的权限类IsAuthenticated会验证该user对象是否存在并且被认证过,如果被认证了那么就会返回Ture,反之亦然。
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
# 在JWTAuthentication认证类里面刚获得user对象user.is_authenticated就已经是Ture了
如果你没有登陆去访问其他接口的话,那么你是以匿名用户AnonymousUser的身份访问的,但是权限认证是不能通过的,但是你要是在视图里的权限类里写空,就比如permission_classes = ( ), 那么你用匿名用户也可以访问该视图,只是没有user信息。
认证类写为空:
权限类写为空:
一般如果要是在登陆认证的接口,那么视图里面的认证和权限类都写空( ),这样不管是自己登陆不需要携带token,写第三方接口时,第三方就能直接调用该接口,不需要token,但是需要你手动的去做一些其他的校验来保证数据的安全