實作 Flask 後端中的 Hash ID 需求
Hash ID
上個學期有個小組的學期作業,要寫一個雲端服務,
我們組的主題是實作出一個功能較多又比較兼顧 UI 的 when2meet
在實作分享功能的時候,
我們希望有一個頁面的資訊(一個叫做 meeting 的 model)可以用網址分享,
讓沒登入的人也可以看得到,
但是這樣的分享方式如果直接用 restful api 的標準的話,
直接使用 api/meetings/<meeting_id>
(這裡 <meeting_id>
是整數)當網址來呼叫需要的 api,
會讓不相干的人直接在 <meeting_id>
打上數字戳進來
所以要使用 hash_id 來實作,
最簡單的方式是直接隨機 random 出一串字串當作 model 的 id,
但我總覺得這樣做很不舒服,
所以我選擇直接拿原來的 id 做 encrypt
流程會變成像下面這樣:
後端 -> id -(encrypt)-> hash_id -> user
至於 encrypt 的方式我選擇使用最簡單的 DES,
多虧大二時的密碼學有稍微認真一下才知道這個名詞XD
DES Encrypt/Decrypt using Python
這個 section 要來記錄一下如何用 python 從 integer id 轉換成 hash_id 的字串(16 進位表示),
又要如何從 hash_id 轉回 id
Installation
1 | pip3 install pycryptodome |
Import
1 | import binascii |
Encrypt (id -> hash_id)
1 | id = 1 |
注意 des.encrypt()
跟 binascii.hexlify()
傳入的東西都需要是 bytes 編碼
Decrypt (hash_id -> id)
知道 encrypt 的步驟後 decrypt 就相對簡單了,
倒著做回來就好
1 | hash_id = '5F6A7D528E394F393C1148C3550B381F' |
Flask Model
再來以當時那個 project 當例子,
來看看在 Flask 中是怎麼實作的,
完整版請點這裡
1 | class Meeting(db.Model): |
基本上跟前一個 section 一樣,
只是 get_id
decrypt 的時候用 try
多檢查一下有沒有 decrypt 成功
在 hash_id
那個 function 我加上了 decorator @property
,
將 hash_id
設為只能讀取不能修改,
因為雖然它的意義很像一個真的存在的 attribute,
因為實際上並沒有一個叫 hash_id
的 attribute,
它的值完全是由 id 轉過來的
另外 @property
還有一個好處,
在使用 Meeting
這個 class 時要像下面這樣
1 | meeting = Meeting() |
注意 hash_id
後面沒有括號,
意義上更像一個 attribute 而不是一個動作 (function) 了,
真棒/
更多有關 @property
的說明可以在這裡找到
而 get_id
我加上了 @staticmethod
的 decorator,
用法就可以像下面這樣
1 | id = Meeting.get_id(hash_id) |
差別在於加上 @staticmethod
就不用每次 get_id
都創一個物件出來,
純呼叫 get_id
的 function 就好
實作 Flask 後端中的 Hash ID 需求
https://tracyliu1220.github.io/2021/03/30/2021-03-30-The-Implementation-of-Hash-ID-using-Flask/