在我们写web项目的时候,一定会遇到关于token的问题,需求可能让你做token认证或者token鉴权,那么两者到底有什么区别呢?
我针对我工作中的python实现token鉴权和认证给大家说一哈。
首先我们应该知道token是什么?
认证
传统的身份验证,就是我们的客户端也就是用户 通过同户名密码来登陆我们的系统,下回再请求的时候,再验证一下,传统解决就是用session和cookie,用户请求的时候返回给客户一个sessionid的字符串,标明这个用户是谁,下次客户请求的时候我们服务器会验证cookie中的信息,找到对应的sessionid就验证通过返回客户想要的信息,但是这样会有一个问题,我们可能会有一个地方存这个sessionid,可能在redis中,要是持久化在mysql中我们可能还要定期处理过期的session。
在我看来token认证可能就是客户端要有登陆,登陆之后再有权利请求别的接口,流程:
1.我们发送请求的时候根据用户名密码请求到server端,
端返回给client端一个加密的token串
3.接下来的每一次请求客户端都可以携带这个加密的token串到server端,这个token串前端可以加在请求头或者直接以参数的形式拼在url后面,后端无论java还是python是可以接收到的。
4.后端判断如果有token我们就可以给客户返回想要的数据。
所以针对以上的问题基于token的验证就不用存储,是一种restful+json的认证方法
但是这个会有一个问题,我在实现的时候就用到了加密解密,python3代码:
#加密算法
import time
import base64
import hmac
def generate_token(key, expire=3600):
ts_str = str(()+expire)
ts_byte = ts_str.encode("utf-8")
#加密
sha1_tshexstr = (("utf-8"),ts_byte,'sha1').hexdigest()
token = ts_str+':'+sha1_tshexstr
b64_token = base64.urlsafe_b64encode(("utf-8"))
return b64_token.decode("utf-8")
我们可能会想,是不是客户端签发了这个token,然后我服务端用一样的加密算法来判断这个token是不是我签发的就能认证是不是我签发的token了,但是不是这样的,我们要是知道,我们会用到()生成当前时间,这个时间是很精确的,客户端发送请求生成到服务端肯定要有个时间差的生成的token一定不一样,所以一定不会通过验证,也就不会走到客户想要数据的相应路由下,也就不会返回数据。
所以我们要用一个解密的方法,代码:
#解密
def certify_token(key, token):
token_str = base64.urlsafe_b64decode(token).decode('utf-8')
token_list = token_str.split(':')
if len(token_list) != 2:
return 0
ts_str = token_list[0]
if float(ts_str) < ():
# token expired
return 0
known_sha1_tsstr = token_list[1]
sha1 = (("utf-8"),ts_str.encode('utf-8'),'sha1')
calc_sha1_tsstr = ()
if calc_sha1_tsstr != known_sha1_tsstr:
# token certification failed
return 0
# token certification success
return 1
我们分析解密代码,如果我们传参,一个我们规定好的key和客户端携带来的我们签发的token,我们解密之后,我们验证我们的key,是相同key就说明密钥相同,是我们签发的,然后还会有个时间,我们验证没有超过我们规定的时间就让客户请求,返回数据。
我当时没有用解密就遇到一个坑:
我想我既然和客户端规定好了密钥,那我不解密,服务端也加密,然后判断两端加密的是不是一样就行了,但是这样问题就出现了,我们一直加密的串都是一样的。这就不对了,所以我们加密的时候要有个当前时间,然后分析时间过期没有,在分析我们的私钥,就能判断是不是可以请求了。
所以我们做token应该都是要解密的,不解密还没有想到该怎么实现。。