Flask-JWT-Extended 組件的使用方法


JWT

JWT(json web token): 頭部、載荷、簽名

頭部 是一個  包含 加密算法和類型的 json字符串,  將字符串進行 base64 編碼之后得到,一個 新的 字符串A

載荷 是一個json字符串, 包含 用戶的身份信息, 將字符串進行 base64 編碼之后得到,一個 新的 字符B, 不建議 存放用戶的 敏感信息,因為 字符串可以被解密

將 字符串A 和字符串B用 . 鏈接, 得到一個新字符串,將新字符串使用密鑰 和 第一部分聲明的加密算法,進行加密,得到字符串C, 而C是不可逆的加C

最后,使用 . 鏈接 每一部分 字符串, 得到 字符串A.字符串B.字符串C
  • 服務器 只需要保留 密鑰和算法,當 收到 客戶端發送的 jwt后,使用 同樣的算法和密鑰進行 解密,解密成功,說明 用戶是合法的;不成功,說明 用戶身份被偽造

  • 本身避免session共享問題

  • 為了避免 csrf 攻擊問題,將 jwt字符串存放到 請求頭中

pip install flask-jwt-extended  # flask項目中使用jwt插件

流程

配置項

import datetime
import os


class Config(object):
   DEBUG = True  # 調試模式
   SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@127.0.0.1:3306/day08'  # 數據庫的地址
   SQLALCHEMY_TRACK_MODIFICATIONS = False  # 默認不追蹤 mysql修改的信號量
   SECRET_KEY = b'\xe6O$\xe8\t\xa5\x7f\xf4\x01#7K\x03\x91\x94d'  # 指明加密的密鑰

   # 構建項目所在的 絕對路徑,也就是 day08 的絕對路徑
   BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
   # 靜態資源存放路徑
   STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
   # 自定義的 圖片上傳路徑
   MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

   JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(days=1)  # 指明token的過期時間
   # JWT_HEADER_TYPE = 'JWT' # 可以修改 請求頭中 ,token字符串的 前綴
   # 默認   Authorization: Bearer <token>
   # 修改: Authorization: JWT <token>

注冊

class RegisterView(Resource):
   def post(self):
       # 1. 創建解析參數對象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的參數
       parser.add_argument('username', type=str, location=['form', 'json'], required=True, help='輸入合法的用戶名')
       parser.add_argument('password', type=str, location=['form', 'json'], required=True, help='輸入安全的密碼')
       # 3. 獲取解析后的參數
       username = parser.parse_args().get('username')
       password = parser.parse_args().get('password')

       # 3.1 校驗 用戶名規則: 字母、數字、_組成, 字母開頭,6-20位
       if not re.match(r'^[a-zA-Z]\w{5,19}$', username):
           return {
                      'msg': '用戶名不合法'
                  }, 400

       # 3.2 校驗用戶名是否重復
       if User.query.filter_by(username=username).count():
           return {
               'msg': '該用戶名已存在'
          }
       
       # 3.3 校驗 密碼規則: 必須存在 數字、 大寫字母、小寫字母, 8-20位
       if not re.match(r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,20}$', password):
           return {
                      'msg': '密碼不安全'
                  }, 400

       # 4. 對密碼進行加密
       new_password = generate_password_hash(password)
       # 5. 創建用戶對象
       user = User(username=username, password=new_password)
       # 6. 將用戶對象添加到 事務中
       db.session.add(user)
       # 7. 提交事務
       db.session.commit()
       # 8. 注冊成功
       return {
           'msg': '用戶注冊成功'
      }

登錄

  • 登錄成功,需要 生成 jwt字符串

    • 在 flask擴展項中,掛載 flask_jwt_extend 插件

    • 在 項目的 配置中,指明 SECRET_KEY 或者 JWT_SECRET_KEY, 密鑰可以使用 os.urandom(n), 指明生成固定長度的密鑰

    • 在 項目的 配置中,指明 JWT_ACCESS_TOKEN_EXPIRES, 也就是 token的過期時間

class LoginView(Resource):
   def post(self):
       # 1. 創建解析參數對象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的參數
       parser.add_argument('username', type=str, location=['form', 'json'], required=True, help='輸入合法的用戶名')
       parser.add_argument('password', type=str, location=['form', 'json'], required=True, help='輸入安全的密碼')
       # 3. 獲取解析后的參數
       username = parser.parse_args().get('username')
       password = parser.parse_args().get('password')

       # 4. 需要從數據庫中查詢 得到 用戶對象
       user = User.query.filter_by(username=username).first()

       # 5. 如果用戶不存在,返回錯誤信息
       if not user:
           return {
                      'msg': '用戶名或密碼錯誤'
                  }, 401

       # 6. 校驗 密碼
       if not check_password_hash(user.password, password):
           return {
                      'msg': '用戶名或密碼錯誤'
                  }, 401

       # 7. 生成token
       token = create_access_token(identity={'id': user.id, 'username': user.username})

       # 8. 返回token
       return {
           'token': token,
           'usernamne': user.username
      }

 

用戶中心 (身份認證)

通過 請求頭中 的 token進行身份認證, 使用 默認提供的 裝飾器進行身份認證

from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity

class UserInfoView(Resource):
   method_decorators = [jwt_required()]

   def get(self):
       # 1. 獲取token中的 載荷信息, 也就是 上一步登錄成功。生成token時,存入 token的信息
       user = get_jwt_identity()

       return user

用戶評論新聞 (實用例)

  • 創建評論表,外鍵關聯 新聞表、用戶表

  • 評論添加時,需要先認證用戶,認證成功,可以獲取用戶id,可以正常發表評論

模型類

# 評論表:
class Comment(db.Model):
   __tablename__ = 'tb_comment'
   id = db.Column(db.Integer, primary_key=True, autoincrement=True)
   content = db.Column(db.String(256))
   news_id = db.Column(db.Integer, db.ForeignKey('tb_news.id'))
   news = db.relationship('News', backref='comments')

   user_id = db.Column(db.Integer, db.ForeignKey('tb_user.id'))
   user = db.relationship('User', backref='comments')

評論添加

from flask_jwt_extended import jwt_required, get_jwt_identity
from flask_restful import Resource, reqparse


# 新聞評論
class NewsCommentView(Resource):
   # 指明當前視圖類所需的裝飾器,也就是 該視圖類的所有方法都需要先 執行裝飾器進行用戶認證
   method_decorators = [jwt_required()]

   def post(self):
       # 1. 創建解析參數對象
       parser = reqparse.RequestParser()
       # 2. 指明需要解析的參數
       parser.add_argument('content', type=str, location=['form', 'json'], required=True, help='輸入評論內容')
       parser.add_argument('news_id', type=int, location=['form', 'json'], required=True, help='請確定評論的新聞')
       # 3. 獲取解析后的參數
       content = parser.parse_args().get('content')
       news_id = parser.parse_args().get('news_id')
       # 從 token的 載荷中獲取用戶id
       user_id = get_jwt_identity().get('id')

       # 4. 創建評論對象
       comment = Comment(content=content, user_id=user_id, news_id=news_id)

       # 6. 將用戶對象添加到 事務中
       db.session.add(comment)
       # 7. 提交事務
       db.session.commit()
       # 8. 注冊成功
       return {
           'msg': '評論成功'
      }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM