19.JWT

JWT

"""
1、组成: 
header.payload.signature 头.载荷.签名

2、距离:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Im93ZW4iLCJleHAiOjE1NTgzMDM1NDR9.4j5QypLwufjpqoScwUB9LYiuhYcTw1y4dPrvnv7DUyo

3:介绍:
header:一般存放如何处理token的方式:加密的算法、是否有签名等
payload:数据的主体部分:用户信息、发行者、过期时间等
signature:签名:将header、payload再结合密码盐整体处理一下
"""

工作原理

"""
1) jwt = base64(头部).base64(载荷).hash256(base64(头部).base(载荷).密钥)
2) base64是可逆的算法、hash256是不可逆的算法
3) 密钥是固定的字符串,保存在服务器
"""

drf-jwt

官网
https://github.com/jpadilla/django-rest-framework-jwt
安装子:虚拟环境
pip install djangorestframework-jwt
使用:user/urls.py
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('login/', obtain_jwt_token),
]
测试接口:post请求
"""
postman发生post请求

接口:http://api.luffy.cn:8000/user/login/

数据:
{
	"username":"admin",
	"password":"admin"
}
"""

drf-jwt开发

配置信息:JWT_AUTH到dev.py中
import datetime
JWT_AUTH = {
    # 过期时间
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
    # 自定义认证结果:见下方序列化user和自定义response
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler',  
}
序列化user:user/serializers.py(自己创建)
from rest_framework import serializers
from .models import User
class UserModelSerializer(serializers.ModelSerializer):
    """轮播图序列化器"""
    class Meta:
        model = User
        fields = ["username", "mobile"]
自定义response:user/utils.py
from .serializers import UserModelSerializers
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'user': UserModelSerializer(user).data
    }
    # restful 规范
    # return {
    #     'status': 0,
    #     'msg': 'OK',
    #     'data': {
    #         'token': token,
    #         'username': user.username
    #     }
    # }

基于drf-jwt的全局认证:user/authentications.py(自己创建)
import jwt
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework.authentication import get_authorization_header
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        # 利用drf获取认证的token,来自请求头的Authorization字段
        jwt_value = get_authorization_header(request)
        # 自定义从请求头的某个字段得到认证的token
        # jwt_value = request.META.get('HTTP_TOKEN', b'')

        # 反扒策略
        jwt_value_list = jwt_value.split()
        if len(jwt_value_list) != 2:
            raise AuthenticationFailed('太长或太短,认证失败')
        if jwt_value_list[0].lower().decode() != api_settings.JWT_AUTH_HEADER_PREFIX.lower():
            raise AuthenticationFailed('没头,认证失败')
        jwt_value = jwt_value_list[1]

        try:
            payload = jwt_decode_handler(jwt_value)
        except jwt.ExpiredSignature:
            raise AuthenticationFailed('过期了,认证失败')
        except jwt.InvalidTokenError:
            raise AuthenticationFailed('非法用户,认证失败')

        user = self.authenticate_credentials(payload)

        return (user, jwt_value)

全局启用:settings/dev.py
REST_FRAMEWORK = {
    # 认证模块
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'user.authentications.JSONWebTokenAuthentication',
    ),
}

局部启用禁用:任何一个cbv类首行
# 局部禁用
authentication_classes = []

# 局部启用
from user.authentications import JSONWebTokenAuthentication
authentication_classes = [JSONWebTokenAuthentication]

多方式登录:user/utils.py
from django.contrib.auth.backends import ModelBackend
from .models import User
import re
class JWTModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        :param request:
        :param username: 前台传入的用户名
        :param password: 前台传入的密码
        :param kwargs:
        :return:
        """
        try:
            if re.match(r'^1[3-9]\d{9}$', username):
                user = User.objects.get(mobile=username)
            elif re.match(r'.*@.*', username):
                user = User.objects.get(email=username)
            else:
                user = User.objects.get(username=username)
        except User.DoesNotExist:
            return None  # 认证失败就返回None即可,jwt就无法删除token
        # 用户存在,密码校验通过,是活着的用户 is_active字段为1
        if user and user.check_password(password) and self.user_can_authenticate(user):
            return user  # 认证通过返回用户,交给jwt生成token

配置多方式登录:settings/dev.py
AUTHENTICATION_BACKENDS = ['user.utils.JWTModelBackend']

手动签发JWT:了解 - 可以拥有原生登录基于Model类user对象签发JWT
from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)


# 了解,原生视图
# 原生APIView可以实现手动签发 jwt
class LoginAPIView(APIView):
    def post(self):
        # 完成手动签发
        pass

posted @ 2021-01-10 22:07  ABDM  阅读(123)  评论(0编辑  收藏  举报