国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Flask后端實踐 連載十一 Flask實現(xiàn)JsonWebToken的用戶認證授權

tips:

  • 本文實現(xiàn)JsonWebToken的用戶認證授權
  • 本文基于python3編寫
  • 代碼倉庫

項目場景

由于公司項目都是前后端分離,需要處理用戶認證方面的問題,以及方便應用的擴展。便采用了JWT的方式。

JWT

JWT認證流程

  • 用戶發(fā)送登陸請求到服務端
  • 服務端驗證用戶的信息
  • 服務端通過驗證發(fā)送給用戶數(shù)據(jù)訪問token和刷新token
  • 客戶端存儲token,并在每次請求時附送上這個token值
  • 服務端驗證token值,并返回數(shù)據(jù)
  • 當服務端驗證token失敗,客戶端使用刷新token刷新數(shù)據(jù)訪問token,并重新請求數(shù)據(jù)。

JWT構成

JWT一共由三部分組成,header(頭部)、payload(載荷)、signature(簽名)。

  1. header,一共兩部分,最后轉(zhuǎn)base64。
    • 類型
    • 加密算法
    {    "type":"JWT",    "alg":"HS256"}
  2. payload,下面的參數(shù)建議都填寫但不是強制使用,也可以自定義載荷,不可以存入敏感信息,最后轉(zhuǎn)base64。
    • iss: jwt簽發(fā)者
    • sub: jwt所面向的用戶
    • aud: 接收jwt的一方
    • exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間
    • nbf: 定義在什么時間之前,該jwt都是不可用的.
    • iat: jwt的簽發(fā)時間
    • jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
    {    "iss":"qin",    "exp":1557715124,    "user_name":"zhang"}
  3. signature,一共三部分。轉(zhuǎn)base64的header和轉(zhuǎn)base64的payload拼接之后,然后使用header中聲明的加密方式和secret加鹽的方式加密字符串。
    • 轉(zhuǎn)base64的header
    • 轉(zhuǎn)base64的payload
    • secret(私鑰)
  4. 生成的token如下所示
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTc3MjI1NTgsImlzcyI6InFpbiIsInVzZXJfbmFtZSI6InpoYW5nIn0.YHNkSdAMEUIY__U5f9e1tQFAdqiHv_ai_gfaPpPnWLc

Flask JWT結合

  1. 安裝PyJWT pip install PyJWT
  2. 編寫刷新token和數(shù)據(jù)請求token生成函數(shù)和解密函數(shù)(util.py)
    from datetime import datetime, timedeltaimport jwtkey = "zkpfw*%$qjrfono@sdko34@%"def generate_access_token(user_name: str = "", algorithm: str = 'HS256', exp: float = 2):    """    生成access_token    :param user_name: 自定義部分    :param algorithm:加密算法    :param exp:過期時間    :return:token    """    now = datetime.utcnow()    exp_datetime = now + timedelta(hours=exp)    access_payload = {        'exp': exp_datetime,        'flag': 0,  # 標識是否為一次性token,0是,1不是        'iat': now,  # 開始時間        'iss': 'qin',  # 簽名        'user_name': user_name  # 自定義部分    }    access_token = jwt.encode(access_payload, key, algorithm=algorithm)    return access_tokendef generate_refresh_token(user_name: str = "", algorithm: str = 'HS256', fresh: float = 30):    """    生成refresh_token    :param user_name: 自定義部分    :param algorithm:加密算法    :param fresh:過期時間    :return:token    """    now = datetime.utcnow()    # 刷新時間為30天    exp_datetime = now + timedelta(days=fresh)    refresh_payload = {        'exp': exp_datetime,        'flag': 1,  # 標識是否為一次性token,0是,1不是        'iat': now,  # 開始時間        'iss': 'qin',  # 簽名,        'user_name': user_name  # 自定義部分    }    refresh_token = jwt.encode(refresh_payload, key, algorithm=algorithm)    return refresh_tokendef decode_auth_token(token: str):    """    解密token    :param token:token字符串    :return:    """    try:        # 取消過期時間驗證        # payload = jwt.decode(token, key, options={'verify_exp': False})        payload = jwt.decode(token, key=key, )    except (jwt.ExpiredSignatureError, jwt.InvalidTokenError, jwt.InvalidSignatureError):        return ""    else:        return payloaddef identify(auth_header: str):    """    用戶鑒權    :return:     """    if auth_header:        payload = decode_auth_token(auth_header)        if not payload:            return False        if "user_name" in payload and "flag" in payload:            if payload["flag"] == 1:                # 用來獲取新access_token的refresh_token無法獲取數(shù)據(jù)                return False            elif payload["flag"] == 0:                return payload["user_name"]            else:                # 其他狀態(tài)暫不允許                return False        else:            return False    else:        return False
  3. 編寫登陸保護函數(shù)(util.py)
    from functools import wrapsdef login_required(f):    """    登陸保護,驗證用戶是否登陸    :param f:    :return:    """    @wraps(f)    def wrapper(*args, **kwargs):        token = request.headers.get("Authorization", default=None)        if not token:            return "請登陸"        user_name = identify(token)        if not user_name:             return "請登陸"        # 獲取到用戶并寫入到session中,方便后續(xù)使用        session["user_name"] = user_name          return f(*args, **kwargs)    return wrapper
  4. 編寫接口(app.py)
    from flask import Flaskfrom util import *app = Flask(__name__)app.config["SECRET_KEY"] = "reqweqwcasd!#$%456421&^%&^%"@app.route('/testLogin', methods=["POST"])def test_login():    """    登陸成功獲取到數(shù)據(jù)獲取token和刷新token    :return:    """    obj = request.get_json(force=True)    name = obj.get("name")    if not obj or not name:        return "參數(shù)錯誤"    if name == "qin":        access_token = generate_access_token(user_name=name)        refresh_token = generate_refresh_token(user_name=name)        data = {"access_token": access_token.decode("utf-8"),         "refresh_token": refresh_token.decode("utf-8")}        return jsonify(data)    else:        return "用戶名或密碼錯誤"@app.route('/testGetData', methods=["GET"])@login_requireddef test_get_data():    """    測試登陸保護下獲取數(shù)據(jù)    :return:    """    name = session.get("user_name")    return "{},你好??!".format(name)@app.route('/testRefreshToken', methods=["GET"])def test_refresh_token():    """    刷新token,獲取新的數(shù)據(jù)獲取token    :return:    """    refresh_token = request.args.get("refresh_token")    if not refresh_token:        return "參數(shù)錯誤"    payload = decode_auth_token(refresh_token)    if not payload:        return "請登陸"    if "user_name" not in payload:        return "請登陸"    access_token = generate_access_token(user_name=payload["user_name"])    data = {"access_token": access_token.decode("utf-8"), "refresh_token": refresh_token}    return jsonify(data)if __name__ == '__main__':    app.run()

測試

  1. 測試登陸
    請求鏈接:http://127.0.0.1:5000/testLogin請求方式:POST請求數(shù)據(jù):{"name":"qin"}數(shù)據(jù)方式:json服務端響應:{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTc3MzM5OTUsImZsYWciOjAsImlhdCI6MTU1NzcyNjc5NSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.PBWk8LOB_S4TVRg7BrXQ9vGjjM31veqgkgbyinVdlVc","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjAzMTg3OTUsImZsYWciOjEsImlhdCI6MTU1NzcyNjc5NSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.kn0-TkP79XlUbCZDeCX7R6oFvG9-M1kYER_7P_d0dTM"}
  2. 測試獲取數(shù)據(jù)
    請求鏈接:http://127.0.0.1:5000/testGetData請求方式:GET請求頭:Authorization = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTc3MzM5OTUsImZsYWciOjAsImlhdCI6MTU1NzcyNjc5NSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.PBWk8LOB_S4TVRg7BrXQ9vGjjM31veqgkgbyinVdlVc服務端響應:qin,你好??!
  3. 測試刷新token
    請求鏈接:http://127.0.0.1:5000/testRefreshToken請求方式:GET請求參數(shù):refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjAzMTg3OTUsImZsYWciOjEsImlhdCI6MTU1NzcyNjc5NSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.kn0-TkP79XlUbCZDeCX7R6oFvG9-M1kYER_7P_d0dTM服務端響應:{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTc3MzQwNjksImZsYWciOjAsImlhdCI6MTU1NzcyNjg2OSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.z-DLcBRRh6pE_wQqfF_YjQMxupbGVI2KD-v9jzEz-H0","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjAzMTg3OTUsImZsYWciOjEsImlhdCI6MTU1NzcyNjc5NSwiaXNzIjoicWluIiwidXNlcl9uYW1lIjoicWluIn0.kn0-TkP79XlUbCZDeCX7R6oFvG9-M1kYER_7P_d0dTM"}

思考

前文只是簡單現(xiàn)實了flask和jwt的結合,實際中使用也會有一定的問題。

  • 第一:載荷可以直接用base64解密。
  • 第二:如果截獲了token,可以利用暴力破解等方式,直接破解加密,提升用戶權限。
  • 第三:一旦拿到刷新token,就可以無限次獲取授權,直到刷新token過期。

一些解決思路:

  • 載荷不存入敏感信息
  • 用戶進行某項關鍵操作,再次驗證用戶。
  • 限制請求次數(shù)
  • 服務端管理token有效性

總結

  • 本文介紹了Flask和JWT的結合,以及實際使用中的一些問題的解決辦法。
  • 下一篇文章將講解一下如果優(yōu)雅的注冊藍圖和自定義的API
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
jwt
第 82 天:Python Web 開發(fā)之 JWT 簡介
使用 JWT 讓你的 RESTful API 更安全
jwt
已復現(xiàn) | nacos身份驗證繞過漏洞(默認token.secret.key)
在線JWT Token解析解碼
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服