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

    你可能感兴趣的文章
    Npp删除选中行的Macro录制方式
    查看>>
    NR,NF,FNR
    查看>>
    nrf24l01+arduino
    查看>>
    nrf开发笔记一开发软件
    查看>>
    nrm —— 快速切换 NPM 源 (附带测速功能)
    查看>>
    nrm报错 [ERR_INVALID_ARG_TYPE]
    查看>>
    NS3 IP首部校验和
    查看>>
    NSDateFormatter的替代方法
    查看>>
    NSError 的使用方法
    查看>>
    NSGA-Ⅲ源代码
    查看>>
    nsis 安装脚本示例(转)
    查看>>
    NSJSON的用法(oc系统自带的解析方法)
    查看>>
    nslookup 的基本知识与命令详解
    查看>>
    NSNumber与NSInteger的区别 -bei
    查看>>
    NSOperation基本操作
    查看>>
    NSRange 范围
    查看>>
    NSSet集合 无序的 不能重复的
    查看>>
    NSURLSession下载和断点续传
    查看>>
    NSUserdefault读书笔记
    查看>>
    NS图绘制工具推荐
    查看>>