cookie、session、token的区别----接口测试(python)中的jwt key 部分Django源码分析

1、Cookie

cookie 是浏览器里面能存储的一种数据,仅仅是存储功能。

cookie由服务器生成,发送给浏览器,浏览器把cookie以键值对的形式保存文件内,以后请求该网站时会发到服务器。cookie是存在客户端上的,故浏览器有一些限制保证cookie不会被恶意使用。同时也不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

接口测试的时候会默认存在requests请求中(python)

2、Session

session 的意思简单来说就是会话。类似在生活中沟通事情,只要一直在进行,这个沟通就没有结束,直到两者不想沟通结束。----需要注意的是,有时候登录服务器通过加密形式返回的session_id本质是token。

类似的道理,服务器要知道跟谁在沟通。为了区分,服务器给客户端分配“身份标识”(字符串),之后向服务器发请求,都带上这个“身份标识”(字符串),服务器就知道沟通(请求)的是谁了,服务器也会有一份校验的标识。沟通的对象(客户端)怎么保存这个“身份标识”,有很多种的形式,浏览器作为客户端一般默认 cookie存储。

cookie、session、token的区别----接口测试(python)中的jwt key 部分Django源码分析_第1张图片

(1)服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

(2)session有有效期,他是指停留在当前页面不操作开始计算,比如设置了2小时,当你操作的时候登录状态一直保持,当你不操作的时候,等过了2小时你再去访问,此时登录就失效了

具体的实现是通过客户端与服务器的对比实现的,一般采用cookie存放session

生成:浏览器第一次访问服务器,服务器会创建一个session,同时为该session生成一个唯一的会话的key,也就是sessionid。

然后,将sessionid及对应的session分别作为key和value保存到缓存中,也可以持久化到数据库中或者redis当中。

服务器再把sessionid,以cookie的形式发送给客户端,这样浏览器下次再访问时,会直接带着cookie中的sessionid,然后服务器根据sessionid找到对应的session进行匹配。

总结:session会在服务器中存放,一般放在redis中,速度会快一些。存session和失效时间,查找session是否失效,从而判断登录状态,如果有效可以进行请求

3、Token

基于token的验证,其实简单来讲就是:

用户登录成功后,服务器通过一系列算法返回一个字符串,以后每次的请求都需要这个串。

复杂来说Token的身份验证过程:

  1. 客户端通过用户名、密码发送请求。
  2. 服务器进行查询数据库、对比登录的验证码等,判断是否登录成功。再通过加密算法(jwt等)生成一个token(签名)。
  3. 服务器将token(签名)回传给客户端。
  4. 客户端把token存下来,变量(接口测试)或Local Storage中(浏览器),并且用于后面的登录成功后发请求。
  5. 服务端校验token并返回数据,校验成功返回客户想要的内容,失败返回错误码。

用图表示就是:

cookie、session、token的区别----接口测试(python)中的jwt key 部分Django源码分析_第2张图片

注意:服务器端校验的时候,不是跟过去的token对比,而是解码判断token数据是否有效,一般判断时间戳

加密算法:

RSA、MD5、SHA

JWT:我们在做接口测试的时候,直接调用登录接口就可以登录成功获取到token。但是有的时候,系统间调用的接口还会用到JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准

在python中是import jwt包(安装pip install jwt,安装出来的是PyJWT),常用的用法是jwt.encode(payload ,key, algorithm)

cookie、session、token的区别----接口测试(python)中的jwt key 部分Django源码分析_第3张图片

payload栽荷:

存放一些标准的内容,比如iss、exp、alg(声明算法)等。非必须

key密钥(也有的写为secret):

与其他系统规定好的密钥(暗号),无默认、必传

algorithm

指明签名算法方式,默认HS256

封装的方法,调用的时候直接get_jwt_encode(key=secret_key, iss=iss)

cookie、session、token的区别----接口测试(python)中的jwt key 部分Django源码分析_第4张图片

使用Django中的JSONWebTokenAuthentication源码和原理

jwt token本质存储的是明文的用户名失效时间等内容

在登录的时候调用  jwt_encode_handler   login_views.py文件

'token': jwt_encode_handler(payload)

在判断是否是登录的时候调用  jwt_decode_handler

JSONWebTokenAuthentication继承
BaseJSONWebTokenAuthentication

1、首先进入authenticate方法

def authenticate(self, request):
    """
 Returns a two-tuple of `User` and token if a valid signature has been
 supplied using JWT-based authentication. Otherwise returns `None`.
 """
 jwt_value = self.get_jwt_value(request)
    if jwt_value is None:
        return None

 try:
        payload = jwt_decode_handler(jwt_value)
    except jwt.ExpiredSignature:
        msg = _('Signature has expired.')
        raise exceptions.AuthenticationFailed(msg)
    except jwt.DecodeError:
        msg = _('Error decoding signature.')
        raise exceptions.AuthenticationFailed(msg)
    except jwt.InvalidTokenError:
        raise exceptions.AuthenticationFailed()

    user = self.authenticate_credentials(payload)

    return (user, jwt_value)

payload = jwt_decode_handler(jwt_value)

2、调用的是rest_framework_jwt模块中的utils的方法

两次jwt.decode参数不一样,返回结果不同,下面判断时间

def jwt_decode_handler(token):
    options = {
        'verify_exp': api_settings.JWT_VERIFY_EXPIRATION,}
 unverified_payload = jwt.decode(token, None, False)
    secret_key = jwt_get_secret_key(unverified_payload)
    return jwt.decode(        

token,api_settings.JWT_PUBLIC_KEY or secret_key, api_settings.JWT_VERIFY,

options=options, leeway=api_settings.JWT_LEEWAY, audience=api_settings.JWT_AUDIENCE, issuer=api_settings.JWT_ISSUER, algorithms=[api_settings.JWT_ALGORITHM])

utils文件中还有jwt_payload_handler方法,用来编码的

有用的是

jwt.decode(token, None, False)
_jwt_global_obj = PyJWT()
encode = _jwt_global_obj.encode
decode = _jwt_global_obj.decode

其中

3、_jwt_global_obj.decode是PyJWT类中的方法

verify用来判断是否校验时间,如果校验使用_validate_claims方法

def decode(self,
 jwt, # type: str
 key='', # type: str
 verify=True, # type: bool
 algorithms=None, # type: List[str]
 options=None, # type: Dict
 **kwargs):

    payload, _, _, _ = self._load(jwt)

    if options is None:
        options = {'verify_signature': verify}
    else:
        options.setdefault('verify_signature', verify)

    decoded = super(PyJWT, self).decode(
        jwt, key=key, algorithms=algorithms, options=options, **kwargs
    )

    try:
        payload = json.loads(decoded.decode('utf-8'))
    except ValueError as e:
        raise DecodeError('Invalid payload string: %s' % e)
    if not isinstance(payload, Mapping):
        raise DecodeError('Invalid payload string: must be a json object')

    if verify:
        merged_options = merge_dict(self.options, options)
        self._validate_claims(payload, merged_options, **kwargs)

    return payload

如果校验时间执行_validate_claims,其中有代码片段,三段,一直到if exp < (now - leeway),现在时间和解析出的时间进行比对

now = timegm(datetime.utcnow().utctimetuple())

if 'exp' in payload and options.get('verify_exp'):
    self._validate_exp(payload, now, leeway)

def _validate_exp(self, payload, now, leeway):
    try:
        exp = int(payload['exp'])
    except ValueError:
        raise DecodeError('Expiration Time claim (exp) must be an'
 ' integer.')

    if exp < (now - leeway):
        raise ExpiredSignatureError('Signature has expired')

4、解码模拟

import jwt

import datetime
import time
# from rest_framework_jwt.utils import jwt_encode_handler
# from rest_framework_jwt.utils import jwt_decode_handler

SECRET_KEY = 'test123'
JWT_SECRET_KEY = SECRET_KEY


# 解码模拟,其中JWT_VERIFY判断是否要校验时间,leeway用来做时间展开
token = ''
test = jwt.decode(token, None, False)
print(test)
time_local = time.localtime(test["exp"])
exp = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
print(exp)

JWT_VERIFY = True
unverified_payload = jwt.decode(token, SECRET_KEY, JWT_VERIFY, leeway=111)
print(unverified_payload)

5、登录时候编码模拟
 

# 编码
payload = {
    'user_id': 24,
 'username': "tch",
 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=0),
 # 'exp': 1682508752
}
# jwt编码在登录中
# jwt_value = jwt_encode_handler(payload)

# 这里面代码会把exp转换成时间戳
jwt_value = jwt.encode(
    payload,
 SECRET_KEY,
 'HS256'
).decode('utf-8')
print(payload)
print(jwt_value)

附录:base64编码和解码

# base64编码和解码
from jwt.utils import base64url_decode, base64url_encode
import base64
# 本质是base64中的urlsafe_b64decode调用b64decode

payload = '1111'.encode('utf-8')
payload_encode = base64url_encode(payload).decode('utf-8')
print(payload_encode)

payload = '2222'.encode('utf-8')
payload_encode = base64url_encode(payload).decode('utf-8')
print(payload_encode)
payload_decode = base64url_decode(a)
print(payload_decode)

你可能感兴趣的:(session,cookie,python,软件测试)