Sanic 是基於 Python 的一個支持高併發的異步 web 框架,sanic-jwt 則是針對Sanic 開發的一個基於 PyJWT 封裝的 JWT 受權認證模塊。html
sanic-jwt 前端
pip install sanic-jwt
下面實例主要總結:git
from sanic import Sanic, request, response from sanic_jwt import initialize, Configuration, Responses, protected, exceptions, Authentication, inject_user class User: def __init__(self, uid, username, sex, password, info, black_level=0): self.user_id = uid self.sex = sex self.username = username self.password = password self.personal_info = info # 只能登陸後我的可見的信息 self.black_level = black_level # 黑名單等級,默認0爲正經常使用戶 def __repr__(self): return "User(id='{}')".format(self.user_id) def to_dict(self): return { "uid": self.user_id, # 注意:此處 "uid" 要與 MyJWTConfig 中的 user_id 設置一致! "sex": self.sex, "username": self.username, "personal_info": self.personal_info } # 模擬一個用戶列表 users = [ User(1, "user1", "男", "123", "這是僅 user1 可見信息", 1), User(2, "user2", "女", "456", "這是僅 user2 可見信息", 0) ] username_table = {u.username: u for u in users} userid_table = {u.user_id: u for u in users} async def authenticate(req: request.Request): username = req.json.get("username", None) password = req.json.get("password", None) if not username or not password: raise exceptions.AuthenticationFailed("用戶名或密碼爲空!") user = username_table.get(username, None) if user is None: raise exceptions.AuthenticationFailed("用戶名或密碼不正確!") if password != user.password: raise exceptions.AuthenticationFailed("用戶名或密碼不正確!") return user class MyJWTConfig(Configuration): # -------------- url_prefix --------------------- # [描述] 獲取受權的路由地址 # [默認] '/auth' url_prefix = '/login' # -------------- secret ------------------------- # [描述] 加密密碼 # [默認] 'This is a big secret. Shhhhh' # [建議] 該密碼是 JWT 的安全核心所在,須要保密,儘可能使用更長更復雜的密碼 secret = ',$FCyFZ^b16#m:ragM#d-!;4!U5zgZDF(EhswOL_HGV#xN1Ll%MaBU42AN=jXgp7' # -------------- expiration_delta ---------------------- # [描述] 過時時間,單位爲秒 # [默認] 30 分鐘,即:60 * 30 # [建議] 該時間不宜過長,同時建議開啓 refresh_token_enabled 以便自動更新 token expiration_delta = 60 * 60 # 改成 10 分鐘過時 # -------------- cookie_set --------------------- # [描述] 是否將獲取到的 token 信息寫入到 cookie # [默認] False,即不寫入cookie # 只有該項爲 True,其它 cookie 相關設置纔會起效。 # cookie_set = True # -------------- cookie_access_token_name --------------- # [描述] cookie 中存儲 token 的名稱。 # [默認] 'access_token' # cookie_access_token_name = "token" # -------------- cookie_access_token_name --------------- # [描述] 包含用戶 id 的用戶對象的鍵或屬性,這裏對應 User 類的用戶惟一標識 # [默認] 'user_id' user_id = "uid" claim_iat = True # 顯示簽發時間,JWT的默認保留字段,在 sanic-jwt 中默認不顯示該項 class MyJWTAuthentication(Authentication): # 從 payload 中解析用戶信息,而後返回查找到的用戶 # args[0]: request # args[1]: payload async def retrieve_user(self, *args, **kwargs): user_id_attribute = self.config.user_id() if not args or len(args) < 2 or user_id_attribute not in args[1]: return {} user_id = dict(args[1]).get(user_id_attribute) # TODO: 根據項目實際狀況進行修改 user = userid_table.get(user_id) return user # 拓展 payload async def extend_payload(self, payload, *args, **kwargs): # 能夠獲取 User 中的一些屬性添加到 payload 中 # 注意:payload 信息是公開的,這裏不要添加敏感信息 user_id_attribute = self.config.user_id() user_id = payload.get(user_id_attribute) # TODO: 根據項目實際狀況進行修改 user: User = userid_table.get(user_id) payload.update({'sex': user.sex}) # 好比添加性別屬性 return payload async def extract_payload(self, req, verify=True, *args, **kwargs): return await super().extract_payload(req, verify) class MyJWTResponse(Responses): # 自定義發生異常的返回數據 @staticmethod def exception_response(req: request.Request, exception: exceptions): # sanic-jwt.exceptions 下面定義的異常類型: # AuthenticationFailed # MissingAuthorizationHeader # MissingAuthorizationCookie # InvalidAuthorizationHeader # MissingRegisteredClaim # Unauthorized msg = str(exception) if exception.status_code == 500: msg = str(exception) elif isinstance(exception, exceptions.AuthenticationFailed): msg = str(exception) else: if "expired" in msg: msg = "受權已失效,請從新登陸!" else: msg = "未受權,請先登陸!" result = { "status": exception.status_code, "data": None, "msg": msg } return response.json(result, status=exception.status_code) app = Sanic("my_auth_app") initialize(app, authenticate=authenticate, authentication_class=MyJWTAuthentication, configuration_class=MyJWTConfig, responses_class=MyJWTResponse) @app.route("/index") @protected() # 保護該路由,只有受權用戶才能訪問 async def protected_route_index(req: request.Request): # 從 request 中獲取 payload,而後返回給前端 payload = await req.app.auth.extract_payload(req) return response.json({'payloadInfo': payload}) @app.route("/info") @inject_user() # 注入用戶信息 @protected() # 保護該路由,只有受權用戶才能訪問 async def protected_route_info(req: request.Request, user: User): if user.black_level == 0: return response.json({'userName': user.username, "personalInfo": user.personal_info}) else: # 進入黑名單等級以後限制查看 return response.json({'userName': user.username, "personalInfo": ""}) if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, auto_reload=True)
下面列出的參數能夠根據須要在前面的 MyJWTConfig 這個類下進行添加設置。github
參數 | 描述 | 默認 | 備註 |
access_token_name
|
標識訪問令牌的key | 'access_token' | |
algorithm
|
生成標記的哈希算法 | 'HS256' 可選項: HS256, HS384, HS512, ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512 |
|
auth_mode
|
是否啓用 /auth 接口 | True | |
authorization_header
|
HTTP請求 header 中令牌key | 'authorization' | |
authorization_header_prefix
|
HTTP請求header中JWT的前綴 | 'Bearer' | |
authorization_header_refresh_prefix
|
保留字,未使用 | 'Refresh' | |
claim_aud
|
面向的用戶 | None | |
claim_iat
|
是否啓用生成令牌簽發時間 | False | |
claim_iss
|
令牌簽發者 | None | |
claim_nbf
|
是否 啓用生成令牌在簽發後多久生效 功能 | False | |
claim_nbf_delta
|
令牌在簽發後多久生效 | 60 * 3,即:3 分鐘 | |
cookie_access_token_name
|
使用cookie令牌時,cookie中令牌的名稱 | 'access_token' | |
cookie_domain
|
cookie所在的域 | '' | |
cookie_httponly
|
是否啓用 http only cookie | True | |
cookie_refresh_token_name
|
使用cookie令牌,cookie中刷新令牌的名稱 | 'refresh_token' | |
cookie_set
|
啓用cookie令牌 | False | |
cookie_strict
|
啓用cookie令牌,cookie獲取失敗後是否禁用頭部令牌 | False | |
cookie_token_name
|
cookie_access_token_name 的別名,用於測試 | False | 實測該值無效,應使用 cookie_access_token_name |
do_protection
|
啓用@protected裝飾器正常工做 | True | |
expiration_delta
|
令牌有效期 | 60 * 5 * 6(30分鐘) | |
generate_refresh_token
|
建立和返回刷新令牌的方法 | sanic_jwt.utils.generate_refresh_token | |
leeway
|
系統時間配置中微小更改的迴旋時間秒 | 60 * 3(3分鐘) | |
path_to_authenticate
|
身份驗證接口路徑 | '/' | |
path_to_refresh
|
刷新令牌接口路徑 | '/refresh' | |
path_to_retrieve_user
|
當前用戶接口路徑 | '/me' | |
path_to_verify
|
令牌驗證接口 | '/verify' | |
private_key
|
用於生成令牌的私鑰,依賴於使用的散列算法 | None | |
public_key
|
secret的別名 | ||
query_string_access_token_name
|
查詢字符串令牌,cookie中令牌的名稱 | 'access_token' | |
query_string_refresh_token_name
|
查詢字符串令牌,cookie中刷新令牌的名稱 | 'refresh_token' | |
query_string_set
|
開啓查詢字符串令牌 | False | |
query_string_strict
|
開啓查詢字符串令牌,查詢字符串不存在是否禁用頭部令牌 | False | |
refresh_token_enabled
|
啓用刷新令牌 | False | 若是開啓,就須要存儲refresh_token, 因此須要額外代碼實現。 |
refresh_token_name
|
刷新令牌的key | 'refresh_token' | |
scopes_enabled
|
啓用scope塊並將做用域添加到jwt payload | False | |
scopes_name
|
jwt payload中scope的key | 'scopes' | |
secret
|
用於哈希算法生成和簽名JWT,每一個應用應該設置自已的值 |
'This is a big secret. Shhhhh' | |
strict_slashes
|
啓用對接口url執行嚴格的/匹配 | False | |
url_prefix
|
sanic jwt默認接口的前綴 | '/auth' | |
user_id
|
包含用戶 id 的用戶對象的鍵或屬性 | 'user_id' | |
verify_exp | 開啓令牌過時驗證 | True | |
sanic-jwtweb
https://blog.csdn.net/zhouping118/article/details/88736986算法