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})

5.总结:

1.token生成后,通过登录接口返回给客户端,然后客户端需在用到用户信息的api接口的请求头带上token
2.python服务端取到请求头中的token,在拦截器中验证token是否失效,做相应的处理
3.mac下安装redis教程:https://www.cnblogs.com/feijl/p/6879929.html
4.下图是client 使用 JWT 与server 交互过程:
token_encode.png
上一篇下一篇

猜你喜欢

热点阅读