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

python 复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

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

服务端加密的过程

第一段字符串

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

第二段字符串

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

第三段字符串

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

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

服务端解密的过程

可以从url中得到用户传递过来的token:requestGET.get("token")

第一部分:我们用base64解密得到头信息

第二部分:我们用base64解密得到自己再token中存储的数据

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

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

user/views

python 复制代码
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)

user/urls

python 复制代码
path("login", LoginView.as_view()),

utils/jwt_auth.py

python 复制代码
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)

测试一下 比如执行某个类下面的方法之前都会先获取token,验证其是否失效

这里验证地址列表,通过url传递token

先登录获取token

获取地址列表

同时终端也打印了信息,说明方法被调用了

utils/jwt_auth.py

再次请求token就失效了,所以我们可以request.user.get("status") 判断用户登录状态是否失效

address/views

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

python 复制代码
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)

DRF-JWT 头信息传递的token验证

utils/jwt_auth.py

python 复制代码
class JwtHeaderAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 从头信息中拿到token
        token = request.META.get("HTTP_TOKEN")
        print(token)
 


DRF-JWT-Token 的全局配置

settings

python 复制代码
# 全局的token验证配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES":['utils.jwt_auth.JwtQueryParamAuthentication']
}

测试

只需要加这两行代码就行

不加的不影响

相关推荐
Wx-bishekaifayuan4 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
独行soc9 小时前
#渗透测试#SRC漏洞挖掘#深入挖掘XSS漏洞02之测试流程
web安全·面试·渗透测试·xss·漏洞挖掘·1024程序员节
小码的头发丝、11 小时前
Django中ListView 和 DetailView类的区别
数据库·python·django
知识的宝藏12 小时前
Django中间件应该怎么使用
中间件·django
千澜空12 小时前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务
竹笋常青13 小时前
《流星落凡尘》
django·numpy
XuanRanDev13 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
coberup18 小时前
django Forbidden (403)错误解决方法
python·django·403错误
鹏大师运维18 小时前
【功能介绍】信创终端系统上各WPS版本的授权差异
linux·wps·授权·麒麟·国产操作系统·1024程序员节·统信uos
亦枫Leonlew19 小时前
微积分复习笔记 Calculus Volume 1 - 4.7 Applied Optimization Problems
笔记·数学·微积分·1024程序员节