博客
关于我
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/

    你可能感兴趣的文章
    Plotly:如何使用 Plotly Express 组合散点图和线图?
    查看>>
    Plotly:如何使用 plotly.graph_objects 和 plotly.express 定义图形中的颜色?
    查看>>
    Plotly:如何使用 Python 对绘图对象条形图进行颜色编码?
    查看>>
    Plotly:如何使用 updatemenus 更新一个特定的跟踪?
    查看>>
    Plotly:如何使用长格式或宽格式的 pandas 数据框制作线图?
    查看>>
    Plotly:如何向烛台图添加交易量
    查看>>
    Plotly:如何在 plotly express 中找到趋势线的系数?
    查看>>
    Plotly:如何在桑基图中设置节点位置?
    查看>>
    pm2 start命令中的json格式详解
    查看>>
    pm2启动报错
    查看>>
    pm2通过配置文件部署nodejs代码到服务器
    查看>>
    PML调用PDMS内核命令研究
    查看>>
    PMM安装-第一篇
    查看>>
    PMP知识要点(第九章)
    查看>>
    PNETLab 镜像包官方下载太慢?不急,最新版本PNET_4.2.10分享!
    查看>>
    POCO库中文编程参考指南(4)Poco::Net::IPAddress
    查看>>
    Quartz基本使用(二)
    查看>>
    POC项目安装与使用指南
    查看>>
    Podman核心技术详解
    查看>>
    pods 终端安装 第三方框架的一些命令
    查看>>