iT邦幫忙

2023 iThome 鐵人賽

DAY 0
0
自我挑戰組

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

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

  • 分享至 

  • xImage
  •  

今日目標

  1. 建立 Register API 並測試。
  2. 重新了解 JWT。
  • 在整理筆記的同時發現自己對於 JWT 還是有點模糊/images/emoticon/emoticon06.gif

    所以打算利用這個機會重新了解這個機制。

建立 Register API 並測試

  • 先將比較單純的 Register API 建立起來。

建立輸入輸出格式

# 輸入
# api_models.py
member_register_model = api.model("MembersRegister", {
    "username": fields.String,
    "password": fields.String,
    "email": fields.String
})
# 輸出
201
{ "message": "Username has been used" }, 409
{ "message": "Email has been used" }, 409

Register 邏輯流程

  • 利用 member_register_model 要求輸入格式。
  • 利用輸入的 username、email 判斷資料庫中是否已經存在相同資料。
  • 將密碼加鹽後 Hash 。
  • 利用輸入的資料以及加鹽後的密碼建立一個新的 Member 加到資料庫中。
# member_controller.py
from werkzeug.security import generate_password_hash
from ...models import generate_salt
@member_ns.route("/member/register")
class MemberRegisterAPI(Resource):

    @member_ns.expect(member_register_model)  # 利用 member_register_model 要求輸入格式
    def post(self):
        # 利用輸入的 username、email 判斷資料庫中是否已經存在相同資料
        if get_member_by_username(member_ns.payload["username"]):
            response = {"message": "Username has been used"}
            return response, 409
        if get_member_by_email(member_ns.payload["email"]):
            response = {"message": "Email has been used"}
            return response, 409
        # 將密碼加鹽後 Hash 
        salt = generate_salt()
        password_hash = generate_password_hash(member_ns.payload["password"]+ salt)
        # 利用輸入的資料以及加鹽後的密碼建立一個新的 Member 加到資料庫中
        addMember(member_ns.payload["username"], member_ns.payload["email"], password_hash, salt)
        return 201

# member_model.py
import secrets

def generate_salt():
  return secrets.token_hex(16)

def get_member_by_username(username):
  return Member.query.filter_by(username=username).first()

def get_member_by_email(email):
  return Member.query.filter_by(email=email).first()

def addMember(username, email, password_hash, salt):
  member = Member(username=username, email=email, password_hash=password_hash, salt=salt)
  db.session.add(member)
  db.session.commit()

測試

  • 上圖片:
  • https://ithelp.ithome.com.tw/upload/images/20230926/20162291jVX0mHYrP1.png
  • https://ithelp.ithome.com.tw/upload/images/20230926/201622919eej9hoWpb.png
  • 測試重複 username:
    • https://ithelp.ithome.com.tw/upload/images/20230926/20162291KvJe3jSwHq.png
  • 測試重複 email:
    • https://ithelp.ithome.com.tw/upload/images/20230926/20162291dvdzHpPpxc.png
    • https://ithelp.ithome.com.tw/upload/images/20230926/20162291X1XDrPZaDm.png

重新了解 JWT

Why

因為 HTTP 協議是無狀態的,意思是說後端不清楚是誰發來的請求,所以需要一個驗證的機制。

以往大多是使用 session 來做驗證,隨著網路環境的發展也產生了一些狀況,而 JWT 機制可以解決這些狀況。

  • session
    • 流程
      • 在用戶登入後,會在後端建立一個 session,同時為這個 session 產生出一組亂數 id。
      • 使用 Response Headers 的 Set-Cookie 讓用戶瀏覽器的將 id 存到 cookie 中。
      • 每次用戶發送 Request,瀏覽器都會自動將 cookie 放到 Request Headers 中一起送出去。
      • 後端在接收到 id 後,去查找對應的 session 來驗證身分。
    • 狀況
      • 跨域問題,例如請求的資源並不在原本的域名上,瀏覽器會限制一個域名設定的 cookie 被另一個域名所讀取,若要解決還需要設定 CORS 。
      • 伺服器擴展問題,例如當使用者流量增加需要有多台伺服器並使用負載平衡器時,當第一次登入時被分配到 a 伺服器建立 session,下次分配到 b 伺服器時就無法讀取之前建立的 session 因此無法識別,若要解決可能要讓所有伺服器的 session 集中起來,需要時都從同一個地方讀取。
  • JWT
    • 流程
      • 在用戶登入後,後端會創建一個包含使用者資訊的 JSON 物件,進行加密並將其簽名。
      • 後端會返回這個 JWT 給用戶,通常通過 Response Body 完成。
      • 每次用戶發送請求必須在 Request Headers( Authorization )中包含 JWT。
      • 當後端接收到 JWT,它會驗證該 JWT 的簽名來驗證身分,並提取令牌中的使用者資訊。
    • 解決狀況
      • 跨域問題:JWT 並不依賴於 cookies,因此同源政策的限制不再適用,這解決了跨域驗證的問題。
      • 伺服器擴展問題:JWT 是無狀態的,意思是後端不需要存儲 JWT 令牌或 session 資訊。當後端接收到一個 JWT,只需要驗證 JWT 的簽名是否有效即可。這樣不論負載平衡器將請求分配到哪個伺服器,都可以獨立驗證 JWT。

HOW

JWT 組成

  • Header、Payload、Signature 彼此以 . 相連組合成一組 JWT 字串。
    • Header
      • 通常包含兩個部分:algtyp,分別代表簽名/加密的算法和令牌類型(通常為 JWT)。
    • Payload
      • 稱為 "claims",內容包含一些使用者訊息與其他數據。
        • Reserved Claims (保留聲明): 這些是預定義的 JWT 聲明,如 iss (issuer, JWT 簽發者), exp (expiration time, 過期時間), sub (subject, 主體, 通常為 user id) 等。
        • Public Claims (公開聲明): 可在 IANA "JWT Claims" 註冊表中登記的聲明。如果使用這些預定義名稱,為避免名稱衝突,通常會使用命名空間做區隔。
        • Private Claims (私有聲明): 這些是自定義的聲明,可以包括特定於應用程序的資訊,例如用戶名稱、角色等。
    • Signature
      • 首先,將 Header 和 Payload 進行 Base64Url 編碼,然後使用 . 將它們串聯起來。
      • 接著使用在 Header 中指定的算法與一個密鑰(secret_key)串聯後的字串進行簽名,以確保令牌的完整性。
  • 線上工具
    https://ithelp.ithome.com.tw/upload/images/20230926/20162291jk9skYs5w1.png

收工

今天將 Register API 完成,並且重新學習了 JWT 的由來、解決的問題、使用流程、實際內容。
明天將開始時做 JWT 的流程啦!!!/images/emoticon/emoticon01.gif


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

尚未有邦友留言

立即登入留言