iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
Vibe Coding

《我與 AI 的奇幻漂流:30 天,把「能跑」變成「能上線」》系列 第 18 篇

【Day 18|辨認來者】Supabase Auth 登入與身分驗證:網站怎麼知道你是誰?

  • 分享至 

  • xImage
  •  

昨天做好的回報功能,不需要知道你是誰。只要內容符合規則,網站就收下。

但收藏不一樣。如果我今天在手機上收藏了一張專輯,晚上回家打開電腦,我希望看到的是同一份清單,而不是重新收藏一次。可是現在的收藏存在瀏覽器裡,換一支手機、換一個瀏覽器,就全部不見了。

要讓收藏跟著人走,網站得先解決一件事:這兩次操作,是同一個人嗎?

今天的重點就在於實作登入功能,來辨識現在使用的人是誰


一、登入功能,要自己從零開始做嗎?

我先問 Codex:「如果這個專案要做使用者登入功能,你建議怎麼做?」它讀完專案後,建議直接沿用現有的 Supabase Auth,不要另外引入其他服務,也不要自己做一套。它會這樣建議,是因為看到專案已經在用 Supabase;換成全新的專案,答案可能就不一樣了。AI 的建議,取決於它看到什麼。

這次 AI 提出的方案很合理,但還是要看得懂它為什麼這樣選。因為登入要處理的事,遠比「確認帳號密碼對不對」多:

要處理的事 為什麼
密碼不能直接存 要先經過不可逆的雜湊處理才能存。注意是雜湊,不是加密:加密可以解回原本的密碼,雜湊不行
記住登入狀態 總不能每換一頁,就再問一次密碼
驗證信箱 確認這個信箱真的是他的
忘記密碼 要能安全地讓使用者重設
擋暴力猜測 有人用程式一直試

這些事,AI 不一定做不到。問題是,我們有必要為了一個登入功能,自己維護整套身分驗證機制嗎?因此我的選擇是畫面自己設計,但底層的身分驗證,優先交給成熟的服務或套件。

1.1 誰來幫你管登入

常見的選擇有這幾種:

選擇 特色
Supabase Auth 跟資料庫在同一個平台,權限規則可以直接認得「目前是誰」
Firebase Authentication Google 生態系的身分驗證服務
Clerk、Auth0 專門做登入的服務,連登入畫面都幫你做好
NextAuth.js、Better Auth 裝在自己專案裡的套件,資料存在自己的資料庫

登入頁可以完全照自己的設計來做。但真正的身分驗證、帳號和登入狀態的管理,直接交給 Supabase 處理。用了 Supabase Auth,不代表登入頁就得長得像 Supabase。
要選擇哪一種,可以自行評估,這篇以 Supabase Auth 舉例。


二、登入的方式,要選哪幾種?

Supabase Auth 登入的方式其實很多種:

方式 使用流程 考量 這次的決定
信箱加密碼 先註冊,之後用密碼登入 大家最熟悉;但要做註冊、忘記密碼、重設密碼,還要處理弱密碼 不做
信箱連結(Magic link) 輸入信箱,點收到的一次性連結 不用記密碼;但常常要在同一個瀏覽器打開才能登入 實作(暫時)
信箱驗證碼(OTP) 輸入信箱,再輸入收到的六位數 不用記密碼,也能換裝置看信;但要自訂信件範本 之後再做
Google 登入 (或其他第三方登入) 交給 Google (其他第三方平台)確認身分 一鍵完成;要到 Google (其他第三方)後台設定 實作

不做密碼登入,是暫時採納了 Codex 的建議:收藏網站使用頻率不固定,很多人會忘記密碼,不做密碼就省掉了忘記密碼、重設密碼、弱密碼這些問題。(但後續可能會加上,畢竟目前很多電子裝置都支援記憶密碼的功能。)

我本來比較想用驗證碼,因為它可以換裝置看信。但驗證碼必須要在信件範本裡加上驗證碼的欄位,而 Supabase 從 2026 年 6 月起,新建立的免費專案如果使用內建的寄信服務,就不能修改信件範本,要先接上自己的寄信服務(SMTP)。所以先用預設的信箱連結來進行示範,過幾天的文章會提到怎麼設定自己的寄信服務,到時候有時間再改成驗證碼。

參考資訊:Supabase:Changes to Email Template Customisation on Free Tier

信箱連結/驗證碼或是 Google 登入還有另外一個好處:可以不用另外做註冊,第一次輸入信箱就是註冊,之後就是登入。


三、先問 AI,再審計畫

決定好方向之後,我先問 Codex:

我想要先完善登入功能,等登入功能完善了,再開始做收藏功能。如果我決定實作 Email 連結+ Google 帳號登入,具體來說需要做哪些事情?有哪些你可以處理?有哪些是需要我去操作的?

接著我又追問了前端、後端、資料庫各會改什麼,以及需不需要加環境變數。

3.1 AI 能做的,和要你做的

AI 能處理 要你自己操作
登入頁、登入狀態、登出 在 Google Cloud 建立 OAuth 應用程式
處理登入回來的那一步(callback) 在 Supabase 後台開啟 Google、貼上金鑰
讓伺服器也讀得到登入狀態 設定 Redirect URLs
檢查 next、處理錯誤 寄信服務、網域、DNS
測試與 build 產品決定,例如要不要開放自動註冊

右邊那欄,我選擇自己處理:有的涉及外部帳號、金鑰和第三方設定,有的是需要我確認的產品決定。有些 AI 工具其實能操作瀏覽器、碰到這些後台,但不是所有能自動化的事,都有必要交給 AI 去做。

3.2 審查清單

AI 給出計畫之後,我會拿這份登入專用的清單對一遍:

要問的問題 為什麼
登入狀態存在哪裡? Next.js 的頁面在伺服器上執行。如果登入狀態只存在瀏覽器裡,伺服器就不知道你是誰,明天的權限規則也會出問題。要存在 cookie 裡,讓伺服器也讀得到
伺服器有沒有再確認一次身分? 伺服器不能直接相信瀏覽器傳來的登入資料,要用 Supabase 建議的方式,驗證這份身分是真的
登入失敗的訊息,會不會洩漏資訊? 不該透露某個信箱有沒有註冊過
登入完要跳轉的網址,有沒有檢查? 第六節細講
哪些功能這次先不做? 大頭貼、修改信箱、刪除帳號、雙重驗證,都可以之後再加

四、先做信箱連結

實作時,我先做信箱連結,Google 留到下一節。

信箱連結幾乎是開箱即用:Supabase 預設就開著信箱登入,內建的寄信服務也能直接寄出登入連結,信件範本不用改。唯一需要做的,是在 Supabase 的 Redirect URLs 加上 http://localhost:3000/auth/confirm,原因看完下面這張圖就知道。

登入頁:輸入信箱,按下寄送
      │  網站請 Supabase 寄信,並附上「登入完要回哪裡」
      │  (/auth/confirm?next=...)
      ▼
Supabase 寄出信件
      │
      ▼
使用者點信裡的連結(連到 Supabase,帶著一次性的 token)
      │  Supabase 確認:連結有效、沒過期、沒被用過
      ▼
回到專案中的 /auth/confirm(網址帶著 code)
      │  用 code,加上瀏覽器先前留下的另一半憑證,
      │  換成登入狀態,存進 cookie
      ▼
跳到指定的登入前頁面

這張圖能解釋三件事:

  • 為什麼 Redirect URLs 要加 /auth/confirm:Supabase 只會把使用者送回允許清單裡的網址,不認得的,就退回首頁
  • 為什麼要在同一個瀏覽器打開:最後一步需要「瀏覽器先前留下的另一半憑證」,換一個瀏覽器,就沒有這一半
  • 登入完回哪裡,是寄信時就決定的:信裡的連結,只是照著第一步寫好的 next 走

https://ithelp.ithome.com.tw/upload/images/20261002/20178017OOPS7UPSUe.png
【圖1|Supabase Redirect URL 設定】

所以如果沒有把http://localhost:3000/auth/confirm 加到Supabase 的 Redirect URLs 的話,其實還是可以登入,只是登入完就會直接回到首頁,不會有我們想要的回到登入前的頁面的功能。

後續有自己的網域之後,Redirect URLs 的地方也要新增http://{{正式網域}}/auth/confirm

測試的時候,很有可能會遇到一個限制:內建的寄信服務,一小時只能寄兩封信。 測了兩次之後,網站就會顯示「寄送次數過多,請稍後再試」。這時可以先用 Google 登入測試跳轉、登出這些流程;正式上線前,建議要接上自己的寄信服務,這件事留到 Day 24。

https://ithelp.ithome.com.tw/upload/images/20261002/20178017EmErNabl5S.png
【圖2|Email 登入信件寄信過於頻繁】

沒有密碼,不代表沒有濫用的風險:風險從「猜密碼」,變成「一直寄信」和「猜連結」。前端的重寄倒數只是讓使用者知道狀況,真正擋得住的,是 Supabase 那一端的次數限制。這跟 Day 17 講的是同一件事:前端擋不住,後端才是真的門。


五、Google 登入:搞懂往返的路線

Google 登入的路線,跟剛剛的信箱連結很像,只是幫你確認身分的,從信箱換成了 Google:

誰幫你確認身分 最後回到網站的哪裡
信箱連結 你的信箱(收得到信,就代表是你) /auth/confirm
Google 登入 Google /auth/callback

兩條路都是:離開網站 → 讓別人確認你是誰 → 帶著憑證回來 → 換成登入狀態。

不同的是,信箱連結開箱即用,Google 登入一定要先設定兩個後台才能用:Supabase 得先跟 Google「認識」。

專案的登入頁
      │  按下「用 Google 登入」
      ▼
Supabase Auth
      │
      ▼
Google 登入與授權畫面
      │  登入成功,Google 回到 Supabase
      ▼
Supabase 的回呼網址(/auth/v1/callback)
      │  確認無誤,回到你的網站
      ▼
專案的 /auth/callback
      │  完成登入、記住登入狀態
      ▼
目標頁面

Google 回到 Supabase,Supabase 才回到我的網站。
登入失敗時,先確認自己卡在哪一段,不要一看到網址錯誤,就到處亂加網址。

這趟往返還藏著一個問題:使用者原本正在看的那張專輯,會不會在離開網站、繞過 Google 和 Supabase 之後,就不見了?所以除了設定網址,還要確認「登入前要回去的頁面」,能一路被帶到最後一步。第六節會細講。

5.1 網址要填在哪裡?

整個流程裡,要填網址的地方有這幾個:

在哪裡 填什麼 要填幾次
Google 後台:已授權的JavaScript 來源 (Authorized JavaScript origins) 允許的網站來源,依你使用的整合方式設定,例如:http://localhost:3000 或是正式網域 依實際需要
Google 後台:已授權的重新導向 URI(Authorized redirect URIs) Supabase 的回呼網址:https://你的專案代號.supabase.co/auth/v1/callback 只要一次
Supabase 後台(Redirect URLs) 你網站的回呼網址:/auth/callback(Google)和 /auth/confirm(信箱連結),localhost、ngrok、正式網域各一組 每多一個網址,就要加一次
程式碼裡 這次登入完,要回到你網站的哪個 callback AI 會處理

在 Google Cloud 設定:

  1. 建立(或選擇)一個 Google Cloud 專案
  2. 點擊「API 與服務」
  3. 設定 「OAuth 同意畫面」:填入應用程式名稱,選擇使用者類型
  4. 建立 「OAuth 用戶端」,類型選「網頁應用程式」
  5. 在 Authorized JavaScript origins 填入 http://localhost:3000 (或是http://正式網域 或http://{{ngrok 測試連結}}
  6. 在 Authorized redirect URIs 填入 Supabase 的回呼網址(可以在 Supabase 後台的 Google 設定頁直接複製,取得方法圖11)
  7. 複製產生的 Client ID 和 Client Secret

https://ithelp.ithome.com.tw/upload/images/20261002/20178017aMVhVRx9XV.png
【圖3|進入 Google Cloud Console 新增專案】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017wp9sj8ClkJ.png
【圖4|選擇 「API與服務」】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017qpFfEppnOI.png
【圖5|選擇 「OAuth 同意畫面」】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017vVAVelJXY8.png
【圖6|「建立 OAuth 用戶端」】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017Fm0Zy2uAP7.png
【圖7|應用程式類型選擇「網頁應用程式」】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017tUSP45JVBt.png
【圖8|填寫對應授權URI、重新導向URI(填寫內容可見上方設定文字敘述第5.6點)】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017RCKocw5Kid.png
【圖9|取得用戶端ID、密碼】

在 Supabase 設定:

  1. Authentication → Sign In / Providers → Google:開啟,貼上剛剛的 Client ID 和 Client Secret
  2. Authentication → URL Configuration:Redirect URLs 加入 http://localhost:3000/auth/callback(Google 用)和 http://localhost:3000/auth/confirm(信箱連結用),之後有 ngrok 或正式網域,再一一加上去(上方圖1)

https://ithelp.ithome.com.tw/upload/images/20261002/20178017BTIQLrbmzJ.png
【圖 10|Supabase 啟用 Google 登入】

https://ithelp.ithome.com.tw/upload/images/20261002/201780177iRIncuR2X.png
【圖 11|將剛剛取得用戶端ID、密碼貼上 Supabase】

ngrok 的網址每一次都會變,所以如果要透過 ngrok 測試登入功能,每一次都要去 supabase Redirect URLs更新 Redirect URLs
此外,可以發現有提供很多第三方登入,也可以去研究。有一些審核可能會比較麻煩(如Facebook),有一些需要付錢(如 Apple,需成為付費開發者才可以設定。)

5.2 只有你自己登得進去?

另一個坑:如果 Google 的同意畫面還在「測試中」,而且使用者類型是「外部」,就只有你手動加進去的測試帳號能登入。你自己測都沒問題,但別人用他的 Google 帳號,就可能會被擋下來。如果有遇到這類問題,可以先確認一下測試的帳號是否是在測試中,填些一些必要資訊後,發布出去,應該就會解決這個問題。


六、登入之後,回到原本的頁面

想像使用者正在看 aespa 的《Armageddon》專輯頁面,他按下收藏,網站發現他還沒登入,就帶他去登入頁。登入完成後,他卻回到了首頁,只好再搜尋一次、再找一次那張專輯。

這不是登入功能能不能運作的問題,而是使用者體驗的問題。就算登入成功,如果還得重新搜尋一次剛剛的專輯,整段操作也算不上順暢。

如果沒有特別交代,登入完通常就是回到首頁或某個固定的頁面。要讓使用者回到原本的地方,做法並不複雜:

  1. 帶使用者去登入頁之前,把他原本所在的頁面記在網址裡,例如 /login?next=原本的頁面
  2. 登入完成後,讀出 next,把他送回那一頁

這也是 Day 11 網址參數的延伸:網址不只能記住篩選條件,也能記住「等一下要回去哪裡」。

next 只是這次取的參數名稱,意思是「登入完要跳轉到哪裡」。名稱可以自己決定,有些網站會用 redirect、redirectTo 或 returnUrl,做的是同一件事。

6.1 怎麼做:網址裡的網址,先編碼

原本的頁面如果也帶參數,例如 /albums/aespa-armageddon?version=superbeing,不能直接塞進 next,否則後面的參數會被當成登入頁自己的。先編碼,把 / 變成 %2F、? 變成 %3F:

/login?next=%2Falbums%2Faespa-armageddon%3Fversion%3Dsuperbeing

另外,信箱連結和 Google 登入都會先離開網站,所以 next 要一路帶到 /auth/confirm 或 /auth/callback,在最後一步才使用。

6.2 注意:next 不能直接相信

網址參數是使用者可以自己改的。如果有人寄給你 /login?next=https://長得很像的假網站.com,你登入完可能就會被帶到假網站,被要求「再輸入一次密碼」。這叫做開放式跳轉。

所以 next 必須設定只接受本站內部的路徑,其他一律回首頁。判斷方式比想像中複雜(// 開頭、反斜線、編碼過的字元都要擋),所以我請 AI 寫成共用的檢查函式,再直接拿惡意網址去測。

昨天,我們不能相信前端送來的 albumId;今天,也不能相信網址裡的 next。

這個檢查不只放在登入頁,真正執行跳轉的 /auth/confirm、/auth/callback 也要使用同一套規則。


七、我曾踩過的坑

坑 原因 解法
信件範本改不了 2026 年 6 月起,新的免費專案用內建寄信服務,就不能改範本 先用預設的信箱連結;要自訂範本,得接上自己的寄信服務(或是付錢升級 supabase 方案)
寄送次數過多 內建寄信服務每小時的額度很少 同上,或是先用 Google 登入測其他流程;正式上線前接上寄信服務
登出後一直顯示「登出中…」 登出的流程卡在瀏覽器那一端 改由伺服器清除登入狀態,再直接跳回首頁(由 AI 處理)
登出了,右上角還顯示已登入 伺服器已經清掉登入狀態,但畫面上那份「目前是誰」沒有跟著更新 伺服器回傳新的登入狀態時,畫面同步更新。瀏覽器和伺服器各記著一份登入狀態,兩邊要同步(由 AI 處理)
從專輯頁登入,回來卻停在帳號頁 初始版本的登入按鈕沒有記下目前在哪一頁,跳轉的預設值為帳號頁或首頁 點登入時帶上目前的頁面,連網址後面的參數一起保留(由 AI 處理)
信箱連結登入後,一律回首頁 Redirect URLs 只加了 Google 用的 /auth/callback,忘了加信箱連結用的 /auth/confirm。Supabase 不認得要回去的網址,就退回預設的首頁 補上 /auth/confirm,並確認登入前的頁面有一路帶到最後一步。允許回到 /auth/confirm,跟保留登入前的頁面,是兩個條件
換瀏覽器打開信箱連結,登不進去 開始登入的瀏覽器會先留下一半的憑證 已知限制,改成驗證碼就不會有這個問題,因此也可能需要付費升級或是街上自己的信件服務

驗收

測試 預期
第一次用信箱連結登入 收到信,點連結後登入,並自動建立帳號
換一個瀏覽器打開信箱連結 照實記錄結果(已知限制)
重新整理、關掉分頁再打開 還是登入狀態
Google 第一次登入 建立帳號,回到網站
同一個信箱,先用信箱連結、再用 Google 登入 不會變成兩個帳號
next=https://別的網站 被擋下來,跳回首頁
next=//別的網站 被擋下來,跳回首頁
next=/\別的網站(反斜線) 被擋下來,跳回首頁
登出 跳回首頁,右上角立刻變成「登入」

這次先不做的事

密碼登入、信箱驗證碼(等 Day 24 接上寄信服務)、大頭貼、暱稱、修改信箱、刪除帳號、雙重驗證。今天暫時只示範一套能支援明天收藏功能的身分系統。

https://ithelp.ithome.com.tw/upload/images/20261002/20178017kWU68BjKg2.png
【圖 12|AI 實作的登入頁面】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017KZJIOkvrQ4.png
【圖 13|填寫 Email 後顯示已寄出】

https://ithelp.ithome.com.tw/upload/images/20261002/20178017h48nWRokCY.png
【圖 14|信箱收到的登入連結】

收到登入信的時候,你可能會覺得說信很醜,或是寄件人跟我的網站無關,看起來不是很專業。前者的話,可以透過 Supabase 後台調整信件模板,透過 HTML 美化信件(但一樣需要設定 SMTP 或是付費升級);後者則是可以用 SMTP 來處理,這在後續的文章會提到。


換個領域:每個產品都要先辨認來者

產品 真正需要辨認的是什麼
記帳 App 同一個使用者,換了裝置也能看到自己的帳目(當然,如果是APP,也可以保存在手機本地,但這樣就無法跨裝置同步)
線上課程 使用者是誰,以及他有沒有買過這堂課
公司內部系統 是不是這個組織的成員(或是說每個成員的權限差異)

登入處理的是「你是誰」;課程能不能看、資料能不能讀,則是下一層的問題。


結語與明日預告

今天,網站終於能回答一個問題:你是誰?

AI 做出一個登入按鈕很容易;但按下去登入成功,不等於整段流程都走通了。信寄不寄得到、Google 的往返、登入後回到哪裡,建議稍微暸解一下,遇到錯誤的時候比較好找出問題在哪裡。

不過,知道你是誰,跟你可以做什麼,是兩件事。我登入之後,網站知道我是誰了。那我是不是就能看到別人的收藏?如果我改一下請求裡的使用者 id,會不會就讀到別人的資料?如果我登出,再換另一個帳號登入,又該看到誰的收藏?

明天,我們來實作收藏功能,並替資料庫加上真正的規則:每個人,只能碰自己的東西。

我們明天見。


上一篇
【Day 17|船舷之外】API 實作與請求驗證:送進來的資料,真的能信嗎?
系列文
《我與 AI 的奇幻漂流:30 天,把「能跑」變成「能上線」》 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言