iT邦幫忙

2023 iThome 鐵人賽

DAY 0
0
自我挑戰組

從零到全端:轉職者的 To-Do List 技能之旅系列 第 13

從零到全端:轉職者的 To-Do List 技能之旅-後端開發- Member API - 4

  • 分享至 

  • xImage
  •  

今日目標

  1. 建立 Rest API 並測試。
  2. 為 Task API 添加 JWT 保護。
  3. 在 swagger UI 中測試 CSRF token。

今天就可以把後端開發的部分做個收尾啦!/images/emoticon/emoticon07.gif

建立 Rest API 並測試

建立輸入輸出規格

  • 依照 Rest API 文件規格:
    • 輸入:email、password(new)。
    • 輸出:message。
    # api_model.py
    reset_input_model = api.model("ResetInput", {
    "email": fields.String,
    "password": fields.String
    })
    reset_output_model = api.model("ResetOutput", {
        "message": fields.String,
    })
    

建立 Rest API

  • Rest API 的邏輯流程
    • 利用 reset_input_model 要求輸入規格。
    • 利用輸入的 email 取得該會員資料。
    • 若會員存在。
      • 利用輸入的資料加鹽 hash。
      • 更新會員資料。
    • 若不存在回傳錯誤。
    # member_controller.py
    @member_ns.route("/reset")
    class MemberResetAPI(Resource):
    
        @member_ns.expect(reset_input_model)
        @member_ns.marshal_with(reset_output_model)
        def post(self):
            member = get_member_by_email(member_ns.payload["email"])
            if member:
                salt = generate_salt()
                password_hash = generate_password_hash(member_ns.payload["password"]+ salt)
                update_member_password_salt(member, password_hash, salt)
                return {"message": "ok"}, 200
            else: 
                return abort(400, "Email does not exist")
    
    #member_model.py
    def get_member_by_email(email):
      return Member.query.filter_by(email=email).first()
    
    def update_member_password_salt(member, password_hash, salt):
      member.password_hash = password_hash
      member.salt = salt
      db.session.commit()
    

測試

  • Email 正確:
    • https://ithelp.ithome.com.tw/upload/images/20230929/201622911SSW7LzL8p.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291ChEQiiJbRU.png
  • Email 錯誤:
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291dNee4RQrh4.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/201622912KKns4JUmi.png

為 Task API 添加 JWT 保護

Create API

  • 添加 @jwt_required()
@tasks_ns.route("") 
class TaskListAPI(Resource):

    @jwt_required()
    @tasks_ns.expect(task_model)
    @tasks_ns.marshal_with(task_model)
    def post(self):
        "Create New Task"
        new_task = get_task_data(tasks_ns)
        task = add_task(new_task)
        return task
  • 設置 Flask-RESTx 的 swagger UI:
    • 在 extensions.py 建立 authorizations 字典。
    • 在 Flask-RESTx 的 Api 實例添加參數 authorizations 為剛建立的字典。
    • 在需要的 API 端口前使用 namespace.doc 裝飾器添加參數 security 為字典中的 key。
# extensions.py
authorizations = { # 建立 authorizations 字典。
    'CSRF': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'X-CSRF-TOKEN'
    },
}

api = Api(title='Todo', doc='/doc', authorizations=authorizations) # Api 實例添加參數 authorizations 為剛建立的字典。

# tasks_controller.py
@tasks_ns.route("") 
class TaskListAPI(Resource):

    @jwt_required()
    @tasks_ns.expect(task_model)
    @tasks_ns.marshal_with(task_model)
    @tasks_ns.doc(security="CSRF") # 使用 namespace.doc 裝飾器添加參數 security 為字典中的 key。
    def post(self):
        "Create New Task"
        jwt_member_id = get_jwt()["id"]
        if not tasks_ns.payload["member_id"] == jwt_member_id: abort(403, "Forbidden")
        new_task = get_task_data(tasks_ns)
        task = add_task(new_task)
        return task

在 swagger UI 中測試 CSRF token

+ swagger UI 登入後取得 CSRF token
    + ![https://ithelp.ithome.com.tw/upload/images/20230929/20162291PgENtwjviy.png](https://ithelp.ithome.com.tw/upload/images/20230929/20162291PgENtwjviy.png)
+ 存放在 UI 中
    + ![https://ithelp.ithome.com.tw/upload/images/20230929/20162291LwJuOCCVGy.png](https://ithelp.ithome.com.tw/upload/images/20230929/20162291LwJuOCCVGy.png)
    + ![https://ithelp.ithome.com.tw/upload/images/20230929/2016229136FHSnybFq.png](https://ithelp.ithome.com.tw/upload/images/20230929/2016229136FHSnybFq.png)

測試

  • 無 cookie:
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291qBNMbVtMWs.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291uB9W34zS85.png
  • 有 cookie 無 CSRF token:
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291GAgh1n2CSv.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/201622917uANHN8s8K.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/201622914C3IyoFXo0.png
  • 添加 CSRF token 在測試:
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291lTrIurAO1S.png
    • https://ithelp.ithome.com.tw/upload/images/20230929/20162291cTzpwZTUAa.png

回顧

總換將後端的部分做一個收尾啦,當然後面部署的時候還要做一些調整。
明天開始要進入前端 React 了!/images/emoticon/emoticon07.gif


上一篇
從零到全端:轉職者的 To-Do List 技能之旅-後端開發- Member API -3
下一篇
從零到全端:轉職者的 To-Do List 技能之旅-前端開發-React-1
系列文
從零到全端:轉職者的 To-Do List 技能之旅15
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言