62 lines
1.8 KiB
Go
62 lines
1.8 KiB
Go
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)
|
|
}
|