博客
关于我
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 多处理 apply_async 永远不会在 Windows 7 上返回结果
    查看>>
    Python 多处理 Numpy 随机
    查看>>
    Python 多处理 >= 125 列表永远不会完成
    查看>>
    Python 多处理:在第一个子错误时中止映射
    查看>>
    Python 多处理不断产生 pythonw.exe 进程而不做任何实际工作
    查看>>
    Python 多处理从不加入
    查看>>
    Python 多处理如何优雅地退出?
    查看>>
    Python 多处理将子进程的标准输出重定向到 Tkinter 文本
    查看>>
    Python 多处理库错误(AttributeError:__exit__)
    查看>>
    Python 多处理模块的 .join() 方法到底在做什么?
    查看>>
    python 多线程与GIL
    查看>>
    Python 多线程学习(转)
    查看>>
    python 多进程-基础
    查看>>
    python 多进程-进阶-进程池
    查看>>
    python 多进程-进阶-进程间通信之Pipe
    查看>>
    python 多进程-进阶-进程间通信之Queue
    查看>>
    Python编程快速入门
    查看>>
    Python编程基础(附Pycharm与开发环境)
    查看>>
    python 如何“否定“value : 如果为真则返回假,如果为假则返回真
    查看>>
    Python 如何在 Web 环境中使用 Matplotlib 进行数据可视化
    查看>>