1.python基於Json Web Token做服務端使用者認證:
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是否失效,做相應的處理
4.下圖是client 使用 JWT 與server 互動過程: