[小專案] 自動辨識藥丸數量的網站

前言 前陣子我的藥師朋友經常需要手動計數藥丸,以便進行包藥作業.這個過程既耗時又容易出錯。為了解決這一問題,我幫他設計了一個簡單的應用程式,使用 YOLOv8 模型來自動識別並計算照片中藥丸的數量,從而快速提供準確的結果 專案說明 專案的詳細介紹我把他整理到 Notion 上,裏面有更詳細的說明 Ref: GitHub Repo 系統架構 這個專案需求非常簡單,其實單純一個 Monolithic 的架構就可以應付,但為了練習看看微服務(Micro service)的切分,就嘗試將不同的功能切分成不同的服務,彼此用 Restful API 溝通 Tech Stack 簡單列一下使用到的技術 Backend Python(FastAPI) Node.js(Express) written in TypeScript Auth JWT Google Auth Redis AI Model YOLOv8 Label-Studio (Labeling Tool) Frontend React written in TypeScript PWA Storage PostgreSQL (database) Minio (Image storage) 心得 這是第一次嘗試 React 的 PWA,用 service worker 滿直覺也滿簡單的,配置一下部署到 Netlify 上,就可以把網站下載到手機桌面上充當一個 APP 使用 這是第一次嘗試 Yolov8 的模型,並使用 Label-Studio 工具作為標註,使用起來相當直覺,當有多人需要同時標註時,簡單在電腦啟動 server,然後用 ngrok 臨時建個 tunnel,開放給別人一起標註...

<span title='2024-07-29 15:50:04 +0800 +0800'>July 29, 2024</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;214 words&nbsp;·&nbsp;Madi

JWT & SendGrid - 實作電商忘記密碼

前言 前陣子參與一個電商的開發案,參考一些開源專案的設計,包含火紅的 Shopify 替代方案-Medusa,研究完後大致了解該怎麼實作和設計一系列跟密碼重設、忘記密碼、註冊登入…等電商功能,所以就有了此篇文章來紀錄一下過程,實作內容是 Medusa 的原始碼,會以一個 high-level 的設計來闡述設計的流程與該注意的事項 以使用者觀點來看忘記密碼/重設密碼這件事 一般來說,我們在用任何有登入、註冊相關的網站,都會有「忘記密碼」的按鈕,但實際上網站後台的資料庫並不會存我們密碼的明碼(理論上都不應該 QQ),所以當按下忘記密碼後,我們會收到一個電子信箱,裡頭並不會原封不動地將我們的密碼傳回來,因為該網站的資料庫存的是 hashed 過後的密碼,而 hash 是無法被逆向回推的,所以這時候信件裡應該是一組 url,點擊後會跳轉到該網站寫好的重設密碼的頁面,讓該使用者輸入密碼與確認密碼,以便重新設定一組新密碼. 例如下圖的 email 截圖,圖片來源: https://designmodo.com/reset-password-emails/ 以上就是一般使用者的操作流程,這些流程大家都再熟悉不過,但背後的系統流程是怎麼運做的呢? 簡述設計流程 既然要收發信件,肯定需要有寄信服務,寄送信件的服務有很多種,最常見的就是SendGrid,我在實作中有註冊一組帳號來取得發送 email 的 token,但後來開發上有受到一些阻礙與問題,最終改用 這篇文章 和 這篇文章 提到的 GCP 支援的 SendGrid Email API 免費方案來完成寄信功能,目前運作起來一切正常 有了寄信服務之後,接下來要解決的是怎麼確保重設密碼的人就是該帳號的擁有者,避免中間過程被盜取身份,竄改該使用者的密碼? 這個問題是最關鍵的,也就是身份認證的資安議題 一般來說,身份認證(Authentication)肯定會需要 DB 來儲存該 user 的個人資料與帳號密碼,因此實作中我使用 PostgreSQL 作為 DB 的選用,而現今認證機制大多使用 JWT,好處是省去 server 再拿 session id 撈一次資料庫的成本,直接用 base64 將 payload 內容 decode,拿到其中就算公開也沒差的無隱私資料,例如:user id,接著服務當場拿該 user id 去問 DB 該 user 的資料,當然也會帶著 JWT token 去詢問,此時 JWT 的第三部分(signature)的 secret 就是判斷該 token 是否有被篡改的依據,若成功驗證,就能成功取得該 user 的資料,完成身份認證(Authentication)甚至授權(Authorization)的流程...

<span title='2023-02-27 00:49:13 +0800 +0800'>February 27, 2023</span>&nbsp;·&nbsp;5 min&nbsp;·&nbsp;923 words&nbsp;·&nbsp;Madi

Node.js - Socket.io 實作多人聊天室

前言 前幾天研究了一下 Client Pull 和 Server Push 的幾種方式,其中屬於 Server Push 的 SSE(Server Send Event)已經在之前的文章 資料實時更新的方式 - Client Pull vs Server Push 中實作過,這次來研究另一種 Server Push 的方式,同時也是較常聽到的 WebSocket,來研究看看如何實作一個簡單的多人聊天室 簡介 Socket.io 因為待會 demo 的前後端會使用 Socket.io 套件來實作,所以開始前先來介紹一下 Socket.io 這個套件 (以下內容整理自官網介紹) Socket.IO is a library that enables low-latency, bidirectional and event-based communication between a client and a server. Socket.io 也是為了解決網路即時通訊而誕生,但是他並不像 WebSocket 一樣屬於通用協定,而是將底層 WebSocket 抽象化的 JavaScript Library(包含前端與後端的 npm 套件),所以 Socket.io 是建於 WebSocket 之上,有自己定義的溝通格式。 Socket.IO is NOT a WebSocket implementation....

<span title='2023-02-10 00:49:13 +0800 +0800'>February 10, 2023</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;585 words&nbsp;·&nbsp;Madi

密碼學中的 Encode(編碼)、Encrypt(加密) 跟 Hash(雜湊) 差異

前言 前陣子用 Node.js 開發時需要用一組加解密的 key 來將某個 url 的 query parameters 加密,就重新回頭研究一下對稱加密與非對稱加密的差異和手段,最後統一用 Node.js 的套件來簡單實作,留下此篇文章以供未來參考 密碼學在學什麼? 密碼學的目標可以簡單列出底下三個: 資訊保密: 確保只有授權者才能取得訊息 完整性驗證: 確保資訊沒有遭到算改 身分驗證: 驗證傳送方與接受方的身分 密碼學主要分為三種,先講結論: Encode(編碼) Two way 的轉換,只是編碼格式的轉換,不需要密碼,所以不算加密,沒有任何資安防護能力 Encrypt(加密) Two way 的轉換,需要密碼介入,可分成對稱加密與非對稱加密,前者是同一把金鑰,後者是有一組公私鑰,有防護資安的能力 Hash(雜湊) One way 的轉換(不可逆),應用 Hashing 的演算法將待加密的字串轉換成一個獨一無二的 hash digest Encode(編碼) 只是換個方式來呈現資料 沒有加密,所以沒有安全性 只是各種平台使用數據的載體,ex: QRCode、UTF-8 為了配合網路傳輸的標準規範(RFC,Requests For Comment),有時就必須透過編碼後才能傳送 Base64 是一種基於 64 個字符來表示的方法 Base64 中的 64 其實是有含意的,他會把資料轉成: a~z (26) A~Z (26) 0~9 (10) + (1) / (1) base64 的 64 就是上面五種字元的所有可能(26+26+10+1+1=64) 打開瀏覽器的 console 介面,用 Web API 就可以開箱及用...

<span title='2023-02-06 19:49:13 +0800 +0800'>February 6, 2023</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;521 words&nbsp;·&nbsp;Madi

資料實時更新的方式 - Client Pull vs Server Push

前言 現今網路世界主要都是用 HTTP request-response 的 model 來做為溝通的模型,client 發送 request 給 server,server 再回傳 response 給 client,但是隨著 Web 的需求改變與技術的演進,漸漸需要另一種溝通方式,來讓 server 無須被 client 請求時就能主動傳送資料給 client,最常見的例子就是股票網站的股價更新、新聞網站的文章更新…等等,或是需要前後端雙方即時溝通的需求,衍生出 WebSockets 的誕生。技術上區分為 Client Pull 和 Server Push 兩種,本篇文章就稍微總結這兩種方式的差異,以及各自有哪些方法 實時更新的幾種方式 主要分成以下幾種方式: Client Pull Short Polling Long Polling Server Push WebSockets SSE (Server Send Event) Short Polling vs Long Polling 早期更新方式是透過 JavaScript 的 Polling(輪詢)來獲得 server 最新的資料 Short polling Short polling 是一個 AJAX-based 的 timer,讓 client 每隔一段時間去向 server 獲取資源,但效能不好,因為有可能 client 每隔 N 秒去問 server 時這 N 秒內資料都沒改動,就會浪費網路資源...

<span title='2023-01-31 00:49:13 +0800 +0800'>January 31, 2023</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;638 words&nbsp;·&nbsp;Madi