python基于Json Web Token做服务端用户认证
2018-08-14 本文已影响225人
许久__
1.python基于Json Web Token做服务端用户认证:
Json Web Token的官方文档地址:https://jwt.io/introduction/,有需要的自行查阅
2.Json Web Token的官方定义:
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,可以在各方之间作为JSON对象安全地传输信息。此信息可以通过数字签名进行验证和信任。 JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
3.Json Web Token的使用场景:
授权(Authorization) 信息交换(Information Exchange)
4.Json Web Token的组成:
JSON Web Tokens由三个部分组成,用点(.)分隔,它们是:Header Payload Signature
1.Header:由两部分组成:令牌的类型,即JWT,以及正在使用的散列算法,例如HMAC SHA256或RSA
例如:这个JSON被编码为Base64Url,形成JWT的第一部分
{
“alg”:“HS256”,
“typ”:“JWT”
}
2.Payload:有效负载,其中包含: registered claims public claims private claims
Registered claims:一组预定义的声明,不是强制性的,但建议使用。如 iss exp sub aud
Public claims:添加自定义的信息,一般添加用户的相关信息与其他业务需要的必要信息,此部分可在客户端解密
Private claims:使用方之间共享信息而创建的自定义声明,为base64是对称解密的,也可解密
例如:这个JSON被编码为Base64Url,形成JWT的第二部分
{
"iat": 1468148739, ##签发的(UNIX时间),可选
"exp": 1478582461, ##过期的(UNIX时间),可选
"authos_id":"10003",
"user_name":"157xxxx4505",
"pass_word":"9a2aac6349b0cd0af564fdb9ffe9e9b5"
}
3.Signature:采用encoded Header,encoded Payload和SECREATE_KEY(一般是随机生成的),通过指定的算法(HMACSHA256),并对其进行加密得到的签名字串
例如:这个JSON被编码为Base64Url,形成JWT的第三部分
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECREATE_KEY
) ##是一段重要的敏感信息,只能在服务端解密
4.将Header Payload Signature用.拼接成一定的字符串,如:
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRob3NfaWQiOiIxMDAwMiIsInVzZXJfbmFtZSI6IjE1NzE3OTE0NTA1IiwiZXhwIjoxNTM0MTY2MDY1Ljg0NjM1OX0.rnCiBKhy17Lb0vxpSZPuGs9-uAu1zNvFjIm-jV62rA8"
使用Json Web Token进行通信:
在redisConn.py文件中,定义一些基本的配置信息:
# jwt配置
jwt_cnf = {
"key_len": 8,
"token_key": "tk_"
}
# redis配置,用于set(token, SECREATE_KEY)
import redis
redis_pool_configs = {
"host": "127.0.0.1",
"port": 6379,
"pool_size": 5, # 0表示不使用连接池 最大连接数
"user_name": "",
"password": "",
"db_name": "fileStore"
}
def engine(redis_config):
configs = dict()
configs['host'] = redis_config['host']
configs['port'] = redis_config['port']
configs['max_connections'] = redis_config['pool_size']
pool = redis.ConnectionPool(**configs)
if redis_config['password'] == '':
r = redis.StrictRedis(connection_pool=pool)
else:
r = redis.StrictRedis(connection_pool=pool, password=redis_config['password'])
return r
# token有效时间配置
ex_time = {
'token_ex': 1
}
# redis
rdc = engine(redis_pool_configs)
在testEnCode.py文件中,处理相应的逻辑:
import jwt
import string
import random
import time
from redisConn import jwt_cnf,ex_time
from redisConn import rdc as redis_service
def generate_key():
#生成长度为8位秘钥字符串
base_str = string.digits + string.ascii_letters
key_list = [random.choice(base_str) for i in range(jwt_cnf['key_len'])]
key_str = "".join(key_list)
return key_str
def create_token(string authos_id,string user_name,string pass_word):
payload = {
"authos_id": authos_id,
"user_name": user_name,
"pass_word": pass_word,
"exp":time.time()+ex_time['token_ex'],
"iat":time.time()
}
key_pix = generate_key() #生成长度为8位秘钥字符串
#生成token字符串
token = jwt.encode(payload, jwt_cnf['token_key'] + key_pix, algorithm='HS256')
redis_service.set(token, jwt_cnf['token_key'] + key_pix)
return True, {'access_token': token, 'authos_id': authos_id}
def check_token(token):
token_key_pix = redis_service.get(token)
try:
# 通过秘钥解密,生成payload
payload = jwt.decode(token,token_key_pix, algorithms=['HS256'])
if payload:
return True, payload
return False, token
except:
# 如果发生异常,则回滚
info = sys.exc_info()
if info[0]:
return False, "token失效"
if __name__ == '__main__':
#代码测试
bool,tokenJson = create_token("10003","157xxxx4505","9a2aac6349b0cd0af564fdb9ffe9e9b5")
print(tokenJson.get("access_token").decode())
#eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRob3NfaWQiOiIxMDAwMyIsInVzZXJfbmFtZSI6IjE1N3h4eHg0NTA1IiwicGFzc193b3JkIjoiOWEyYWFjNjM0OWIwY2QwYWY1NjRmZGI5ZmZlOWU5YjUiLCJpYXQiOjE1MzQyNTY2MTYuNTkxMjY5LCJleHAiOjE1MzQyNTY2MTcuNTkxMjY5fQ.ydWFF_O60vRk6U0kjlGI_0_8fD41qvZ-yF1DBxIVdTQ
print(check_token(tokenJson.get("access_token").decode()))
#(True, {'authos_id': '10003', 'user_name': '157xxxx4505', 'pass_word': '9a2aac6349b0cd0af564fdb9ffe9e9b5', 'iat': 1534256616.591269, 'exp': 1534256617.591269})