116 lines
3.0 KiB
Go
116 lines
3.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"stocksearch/config"
|
|
"stocksearch/middleware"
|
|
"stocksearch/services"
|
|
)
|
|
|
|
// AuthHandler 로그인/로그아웃 핸들러
|
|
type AuthHandler struct {
|
|
sessionSvc *services.SessionService
|
|
loginTmpl *template.Template
|
|
}
|
|
|
|
// NewAuthHandler 인증 핸들러 초기화
|
|
func NewAuthHandler(sessionSvc *services.SessionService) *AuthHandler {
|
|
tmpl, err := template.ParseFiles("templates/pages/login.html")
|
|
if err != nil {
|
|
log.Fatalf("로그인 템플릿 파싱 실패: %v", err)
|
|
}
|
|
return &AuthHandler{
|
|
sessionSvc: sessionSvc,
|
|
loginTmpl: tmpl,
|
|
}
|
|
}
|
|
|
|
// LoginPage GET /login — 로그인 폼 렌더링
|
|
func (h *AuthHandler) LoginPage(w http.ResponseWriter, r *http.Request) {
|
|
// 이미 로그인된 경우 메인으로 리다이렉트
|
|
if cookie, err := r.Cookie(middleware.SessionCookieName); err == nil {
|
|
if h.sessionSvc.Validate(cookie.Value) {
|
|
http.Redirect(w, r, "/", http.StatusFound)
|
|
return
|
|
}
|
|
}
|
|
// next 파라미터가 없으면 로그인 후 메인 페이지로
|
|
next := r.URL.Query().Get("next")
|
|
if next == "" {
|
|
next = "/"
|
|
}
|
|
data := map[string]string{
|
|
"Next": next,
|
|
"Error": "",
|
|
}
|
|
h.renderLogin(w, data)
|
|
}
|
|
|
|
// Login POST /login — ID/PW 검증 후 세션 발급
|
|
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "잘못된 요청입니다.", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
id := r.FormValue("id")
|
|
password := r.FormValue("password")
|
|
next := r.FormValue("next")
|
|
if next == "" {
|
|
next = "/"
|
|
}
|
|
|
|
// ID/PW 검증
|
|
if id != config.App.AdminID || password != config.App.AdminPassword {
|
|
data := map[string]string{
|
|
"Next": next,
|
|
"Error": "아이디 또는 비밀번호가 올바르지 않습니다.",
|
|
}
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
h.renderLogin(w, data)
|
|
return
|
|
}
|
|
|
|
// 세션 생성 및 쿠키 설정
|
|
sessionID := h.sessionSvc.Create()
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: middleware.SessionCookieName,
|
|
Value: sessionID,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
MaxAge: 86400, // 24시간
|
|
})
|
|
|
|
http.Redirect(w, r, next, http.StatusFound)
|
|
}
|
|
|
|
// Logout POST /logout — 세션 삭제 후 /login 리다이렉트
|
|
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
|
if cookie, err := r.Cookie(middleware.SessionCookieName); err == nil {
|
|
h.sessionSvc.Delete(cookie.Value)
|
|
}
|
|
|
|
// 쿠키 만료 처리
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: middleware.SessionCookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
MaxAge: -1,
|
|
})
|
|
|
|
http.Redirect(w, r, "/", http.StatusFound)
|
|
}
|
|
|
|
// renderLogin 로그인 템플릿 렌더링 헬퍼
|
|
func (h *AuthHandler) renderLogin(w http.ResponseWriter, data interface{}) {
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
if err := h.loginTmpl.ExecuteTemplate(w, "login.html", data); err != nil {
|
|
log.Printf("로그인 템플릿 렌더링 실패: %v", err)
|
|
http.Error(w, "페이지를 표시할 수 없습니다.", http.StatusInternalServerError)
|
|
}
|
|
}
|