• Django token 认证原理与实战


    概述 cookie、session 与token 的区别

    Cookie的作用

    1. cookie的存储量很小,一般不超过4K
    2. cookie并不会保存很多信息,一般用来存储登录状态
    3. cookie是以键值对进行表示的(key=value),例如name=li,表示cookie的名字是name,cookie携带的值是li
    4. cookie的存储分为会话存储和持久性存储
    5. 如果cookie会话性那么cookie仅会保存在客户端内存中,当我们关闭客户端时cookie就会失效
    6. 如果cookie为持久性,那么cookie会保存到硬盘中直至生存期结束或者用户主动将其销毁

    Session是什么

    1. 在网络应用中成为会话控制
    2. Session用来存储特定用户会话所需的属性及配置等信息
    3. session保存的位置在服务端

    为什么需要session

    1. 我们目前使用的互联网应用层协议基本上都是基于HTTP和HTTPS
    2. HTTP和HTTPS是无状态的,只负责请求和响应
    3. 所以导致如果没有额外处理的话服务器是不知道你是谁,更无法根据你是谁给你展现和你相关的内容

    cookie存储在客户端,session存储在服务端,浏览器请求时将cookie携带至后端,服务端根据cookie中的关键信息找到对应的session,用来保持会话

    什么是token

    • token其实就是一段加密的字符串
    • 一般由身份标识,时间戳,用户必要信息等内容组成
    • tonken的传输就是一个加密和解密的过程

    可以看到 服务端是不保存token的
    在这里插入图片描述

    JWT–JsonWebToken 实现原理

    jwt

    在这里插入图片描述

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    
    • 1

    它是一个由.连接组成的三段字符串

    服务端加密的过程

    第一段字符串
    是头信息,头信息包含算法和算法类型,这部分字符串由头信息进行base64加密得到的,它是token的第一段字符串

    第二段字符串
    是我们自己定义或者存储的一些信息,可以包含用户名过期时间等,然后对此进行base64加密得到token第二段字符串

    第三段字符串

    第一段base64加上一个.然后加上第二段base64再加上“密钥”,然后再来一个base64最后生成了token第三段字符串

    以上3段字符串通过.进行连接生成最后的token返回给客户端

    服务端解密的过程
    可以从url中得到用户传递过来的token:requestGET.get(“token”)

    第一部分:我们用base64解密得到头信息
    第二部分:我们用base64解密得到自己再token中存储的数据
    第三部分:把第一个部分加第二部分内容再加上我们自己的密钥进行base64加密得到一个base64字符串,最后用这个字符串和用户传递的第三部分进行比较

    DRF-JWT 用户登录认证实现(一)

    user/views

    class LoginView(GenericAPIView):
        def post(self,request):
            return_data = {}
            request_data = request.data
            email = request_data.get("username")
            user_data = User.objects.get(email=email)
            if not user_data:
                return ResponseMessage.UserResponse.other("用户名或者是密码错误1")
            else:
                user_ser = UserSerializer(instance=user_data,many=False)
                # 用户输入的密码
                user_password = request_data.get("password")
                md5_user_password = get_md5(user_password)
                print(md5_user_password)
                # 数据库的密码
                db_user_password = user_ser.data.get("password")
                print(db_user_password)
                if md5_user_password != db_user_password:
                    return ResponseMessage.UserResponse.other("用户名或者是密码错误2")
                else:
                    token_info = {
                        "username":email
                    }
                    token_data = create_token(token_info)
                    return_data["token"] = token_data
                    return_data["username"] = user_ser.data.get("name")
                    return ResponseMessage.UserResponse.success(return_data)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    user/urls

    path("login", LoginView.as_view()),
    
    • 1

    utils/jwt_auth.py

    import datetime
    
    import jwt
    from rest_framework.authentication import BaseAuthentication
    
    from muxi_shop_back.settings import SECRET_KEY
    
    
    def create_token(payload,timeout=1):
        headers = {
            'alg':"HS256",
            'typ':"jwt"
        }
        payload["exp"] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    
        result = jwt.encode(headers=headers,payload=payload,key=SECRET_KEY,algorithm="HS256")
        return result
    
    def get_payload(token):
        result = {"status":False,"data":None,"error":None}
        try:
             payload = jwt.decode(token,SECRET_KEY,algorithms=["HS256"])
             result["status"] = True
             result["data"] = payload
        except jwt.exceptions.DecodeError:
            print("token认证失败了")
            result["error"] = "token认证失败了"
        except jwt.exceptions.ExpiredSignatureError:
            print("token已经失效了")
            result["error"] = "token已经失效了"
        except jwt.exceptions.InvalidTokenError:
            print("无效的、非法的token")
            result["error"] = "无效的、非法的token"
        return result
    
    # 用户在url中进行token的参数配置
    class JwtQueryParamAuthentication(BaseAuthentication):
        def authenticate(self, request):
            # 从url中拿到token
            token = request.GET.get("token")
            result_payload = get_payload(token)
            print(result_payload)
            return (result_payload,token)
    
    class JwtHeaderAuthentication(BaseAuthentication):
        def authenticate(self, request):
            # 从头信息中拿到token
            token = request.META.get("HTTP_TOKEN")
            print(token)
            result_payload = get_payload(token)
            print(result_payload)
            return (result_payload,token)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    测试一下 比如执行某个类下面的方法之前都会先获取token,验证其是否失效
    这里验证地址列表,通过url传递token
    在这里插入图片描述
    先登录获取token
    在这里插入图片描述
    获取地址列表
    在这里插入图片描述

    同时终端也打印了信息,说明方法被调用了
    utils/jwt_auth.py
    在这里插入图片描述

    在这里插入图片描述

    再次请求token就失效了,所以我们可以request.user.get(“status”) 判断用户登录状态是否失效
    在这里插入图片描述

    address/views

    把定义的验证类加在该方法下,表明访问即验证token

    class AddressListGenericAPIView(GenericAPIView,ListModelMixin):
        queryset = UserAddress.objects
        serializer_class = AddressSerializer
        authentication_classes = [JwtQueryParamAuthentication, ]
    
        def get(self, request):
            # 拿到token验证返回的第一个值
            print(request.user)
            # 拿到token返回的第二个值
            print(request.auth)
            # 加该逻辑即进行验证
            if not request.user.get("status"):
                return JsonResponse(request.user, safe=False)
    
            return self.list(request)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    DRF-JWT 头信息传递的token验证
    utils/jwt_auth.py

    class JwtHeaderAuthentication(BaseAuthentication):
        def authenticate(self, request):
            # 从头信息中拿到token
            token = request.META.get("HTTP_TOKEN")
            print(token)
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    DRF-JWT-Token 的全局配置

    settings

    
    # 全局的token验证配置
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":['utils.jwt_auth.JwtQueryParamAuthentication']
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试
    只需要加这两行代码就行
    在这里插入图片描述
    在这里插入图片描述

    不加的不影响
    在这里插入图片描述

  • 相关阅读:
    Python解释器与Python编辑器的详细下载与安装过程
    如何判断自己适不适合做一名程序员
    管理学培养目标及就业前景
    融云 Flutter SDK,跨平台开发的真香之选
    美团2024届秋招笔试第一场编程【代码】
    c语言进制的转换16进制转换2进制
    JAVA毕设项目商品供应管理系统(java+VUE+Mybatis+Maven+Mysql)
    Android渲染一个列表的过程,并提供动态改变样式
    2022年IC行业还缺人吗?
    DTSE Tech Talk丨第3期:解密数据隔离方案,让SaaS应用开发更轻松
  • 原文地址:https://blog.csdn.net/weixin_47906106/article/details/134012469