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

    你可能感兴趣的文章
    net包之IPConn
    查看>>
    NFinal学习笔记 02—NFinalBuild
    查看>>
    NFS共享文件系统搭建
    查看>>
    nfs复习
    查看>>
    NFS网络文件系统
    查看>>
    nft文件传输_利用remoting实现文件传输-.NET教程,远程及网络应用
    查看>>
    ng 指令的自定义、使用
    查看>>
    Nginx
    查看>>
    nginx + etcd 动态负载均衡实践(二)—— 组件安装
    查看>>
    nginx + etcd 动态负载均衡实践(四)—— 基于confd实现
    查看>>
    Nginx + Spring Boot 实现负载均衡
    查看>>
    Nginx + uWSGI + Flask + Vhost
    查看>>
    Nginx - Header详解
    查看>>
    Nginx Location配置总结
    查看>>
    Nginx upstream性能优化
    查看>>
    Nginx 中解决跨域问题
    查看>>
    Nginx 动静分离与负载均衡的实现
    查看>>
    Nginx 反向代理 MinIO 及 ruoyi-vue-pro 配置 MinIO 详解
    查看>>
    nginx 反向代理 转发请求时,有时好有时没反应,产生原因及解决
    查看>>
    Nginx 反向代理解决跨域问题
    查看>>