博客
关于我
JWT认证 基础及高级应用
阅读量:208 次
发布时间:2019-02-28

本文共 4524 字,大约阅读时间需要 15 分钟。

JWT认证

JWT的本质

在用户注册或登录后,我们需要记录用户的登录状态或为用户创建身份认证的凭证。与传统的Session认证机制不同,JWT(Json Web Token)采用token的方式进行认证。

JWT的核心原理

  • 签发和校验:
    • 签发:根据登录请求提交的账号、密码及设备信息,生成Token。
    • 校验:根据客户端提交的Token,反解出用户对象。
  • JWT的构成

    JWT由三部分组成:Header(头部)、Payload(载荷)、Signature(签名)。

    1. Header(头部)

    • 包含两部分信息:
      • typ: JWT(声明类型)。
      • alg: 加密算法(通常为HMAC SHA256)。
    • 通过Base64加密,生成第一部分。

    2. Payload(载荷)

    包含以下信息:

    • 标准声明(可选):iss(签发者)、sub(面向的用户)、aud(接收方)、exp(过期时间)、nbf(不可用时间)、iat(签发时间)、jti(唯一身份标识)。
    • 公共声明:可添加用户相关信息或其他业务信息。
    • 私有声明:由提供者和消费者共同定义,通常不建议存放敏感信息。

    3. Signature(签名)

    • 由加密后的Header、Payload及服务器私钥组成。
    • 通过HMAC SHA256算法生成。

    JWT的高级用法

    1. 自定义返回数据格式

    • 方式一:自定义登录接口。
    • 方式二:使用内置方法,通过配置文件控制返回格式。
    # 配置文件JWT_AUTH = {    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.new_jwt_response_payload_handler'}

    2. 自定义基于JWT的权限类

    from rest_framework_jwt.utils import jwt_response_payload_handler, jwt_decode_handlerfrom rest_framework_jwt.authentication import BaseJSONWebTokenAuthenticationfrom rest_framework.exceptions import AuthenticationFailedimport jwtfrom app.views import modelsclass New_JWT_Authentication(BaseJSONWebTokenAuthentication):    def authenticate(self, request):        jwt_value = self.request.META.get('HTTP_AUTHORIZATION')        if jwt_value is None:            raise AuthenticationFailed('您没有携带认证信息')        try:            payload = jwt_decode_handler(jwt_value)        except jwt.ExpiredSignature:            raise AuthenticationFailed('签名过期')        except jwt.DecodeError:            raise AuthenticationFailed('签名解码出错')        except jwt.InvalidTokenError:            raise AuthenticationFailed('非法用户')        except Exception as e:            raise AuthenticationFailed(str(e))                user = self.authenticate_credentials(payload)        return (user, jwt_value)

    3. JWT配置过期时间

    import datetimeJWT_AUTH = {    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7)}

    4. 手动签发Token(多方登录)

    1. 序列化类
    from rest_framework import serializersfrom rest_framework.exceptions import ValidationErrorfrom rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handlerfrom app import modelsimport reclass LoginSer(serializers.ModelSerializer):    username = serializers.CharField()        class Meta:        model = models.E_User        fields = ['username', 'password']        def validate(self, attrs):        username = attrs.get('username')        password = attrs.get('password')        if re.match('^1[3-9][0-9]{9}$', username):            userobj = models.E_User.objects.filter(mobile=username).first()        elif re.match('^.*@.*$', username):            userobj = models.E_User.objects.filter(email=username).first()        else:            userobj = models.E_User.objects.filter(username=username).first()        if userobj:            if userobj.check_password(password):                payload = jwt_payload_handler(userobj)                token = jwt_encode_handler(payload)                attrs['token'] = token                return attrs            else:                raise ValidationError('密码错误')        else:            raise ValidationError('用户不存在')
    2. 视图类
    class LoginView(ViewSet):    def login(self, request):        login_user = app_ser.LoginSer(data=request.data)        login_user.is_valid(raise_exception=True)        token = login_user.data.get('token')        username = login_user.data.get('username')        return Response({            'status': 100,            'msg': '登录成功',            'token': token,            'username': username        })
    3. 多方登录的实现
    class LoginSer1(serializers.ModelSerializer):    username = serializers.CharField()class Login2View(ViewSet):    def login(self, request):        username = request.data.get('username')        password = request.data.get('password')        if re.match('^1[3-9][0-9]{9}$', username):            userobj = models.E_User.objects.filter(mobile=username).first()        elif re.match('^.*@.*$', username):            userobj = models.E_User.objects.filter(email=username).first()        else:            userobj = models.E_User.objects.filter(username=username).first()        if userobj:            if userobj.check_password(password):                payload = jwt_payload_handler(userobj)                token = jwt_encode_handler(payload)                loginser = LoginSer1(data=request.data)                loginser.is_valid(raise_exception=True)                loginser.validated_data['token'] = token                loginser.validated_data.pop('password')                return Response(loginser.validated_data)            else:                return Response('密码错误')        else:            return Response('用户名不存在')

    转载地址:http://pfvp.baihongyu.com/

    你可能感兴趣的文章
    Python:爬取数据出现response.status_code为418解决方法
    查看>>
    Python:生成“元组集“;来自“元组列表“;不考虑顺序
    查看>>
    Python:生成具有趋势的随机时间序列数据(例如周期性、指数衰减等)
    查看>>
    Python:用渐进式数字重命名列表中的重复项而不对列表进行排序
    查看>>
    Python:矩形参数无效
    查看>>
    Python:语法进阶
    查看>>
    Python:调用复制函数时调用 Python 对象时超出了最大递归深度
    查看>>
    Python:这两个 import 语句有什么区别?
    查看>>
    Python:通过串口从 Velleman k8090 读取数据
    查看>>
    python:遍历具有列表值的字典
    查看>>
    Python:降低精度 pandas 时间戳数据帧
    查看>>
    python:非阻塞子进程,检查标准输出
    查看>>
    PythonABC多重继承
    查看>>
    Pythonargparse中的多个参数
    查看>>
    Python关于 *args 和 **kwargs 参数的详解(全)
    查看>>
    Pythonfrozenset散列算法/实现
    查看>>
    PythonGTK+3:通过单击列对树视图进行排序
    查看>>
    pythonnumpy生成二进制流_python/numpy生成的二进制文件,由C读取
    查看>>
    pythonsign函数_对python函数签名的方法详解 用python怎么写一个自签名证书
    查看>>
    PythonStudy
    查看>>