This commit is contained in:
2026-10-05 07:40:34 +08:00
parent 5a7ac2e5d9
commit d13088bfd5
22 changed files with 1369 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
package handlers
import (
"errors"
"net/http"
"strings"
"nestly/internal/models"
)
// loginView 登入頁的模板資料。
type loginView struct {
Email string
Error string
}
// AuthHandler 處理登入與登出。
type AuthHandler struct {
deps Dependencies
}
// Login 渲染登入頁;已登入者直接導向首頁。
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
if _, err := h.deps.Sessions.UserID(r); err == nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
if err := h.deps.Templates.Render(w, http.StatusOK, "login.html", loginView{}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// DoLogin 驗證 Email 與密碼,成功後建立 session 並導向首頁;
// 失敗時重新渲染表單並保留使用者輸入的 Email。
func (h *AuthHandler) DoLogin(w http.ResponseWriter, r *http.Request) {
email := strings.TrimSpace(r.PostFormValue("email"))
password := r.PostFormValue("password")
// 帳號不存在與密碼錯誤回應同一訊息,避免列舉有效 Email。
view := loginView{Email: email}
acct, err := h.deps.Accounts.FindByEmail(r.Context(), email)
if err != nil && !errors.Is(err, models.ErrNotFound) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err == nil && acct.VerifyPassword(password) {
h.deps.Sessions.Login(w, acct.ID)
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
view.Error = "Email 或密碼不正確。"
if err := h.deps.Templates.Render(w, http.StatusUnauthorized, "login.html", view); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// Logout 清除 session 並回到登入頁。
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
h.deps.Sessions.Logout(w)
http.Redirect(w, r, "/login", http.StatusSeeOther)
}