Files
stocksearch/middleware/auth.go
hayato5246 5aeb5f2b80
Some checks failed
Build Push and Restart Compose / deploy (push) Failing after 11m20s
자산 현황 및 자동매매 페이지 제거:
- `/templates/pages/asset.html`, `/templates/pages/autotrade.html` HTML 템플릿 삭제.
- `/static/js/asset.js`, `/static/js/autotrade.js` 클라이언트 스크립트 제거.
- 관련 함수 및 초기화 로직 삭제 (자산 조회 및 자동매매 기능 비활성화).
2026-04-07 21:43:24 +09:00

102 lines
2.7 KiB
Go

package middleware
import (
"context"
"net/http"
"stocksearch/services"
"strings"
)
const SessionCookieName = "ss_session"
// contextKey 컨텍스트 키 타입
type contextKey string
const CtxLoggedIn contextKey = "loggedIn"
// IsLoggedIn 요청 컨텍스트에서 로그인 여부 반환
func IsLoggedIn(r *http.Request) bool {
v, _ := r.Context().Value(CtxLoggedIn).(bool)
return v
}
// publicPaths 로그인 없이 접근 가능한 경로 (전체 일치 또는 prefix)
var publicPaths = []string{
"/login",
// 공개 페이지
"/",
"/theme",
"/kospi200",
"/stock/",
// 공개 API (시세/테마/코스피200 관련)
"/api/stock/",
"/api/indices",
"/api/search",
"/api/scanner/",
"/api/signal",
"/api/watchlist-signal",
"/api/themes",
"/api/themes/",
"/api/kospi200",
"/api/news",
"/api/disclosure",
"/api/auth/check",
"/api/watchlist",
"/ws",
}
// isPublic 요청 경로가 공개 경로에 해당하는지 판단
func isPublic(path string) bool {
for _, p := range publicPaths {
if strings.HasSuffix(p, "/") {
if strings.HasPrefix(path, p) || path == p[:len(p)-1] {
return true
}
} else {
if path == p {
return true
}
}
}
return false
}
// Auth 세션 쿠키 검증 미들웨어
// - 공개 경로: 로그인 없이 접근 허용
// - 인증 필요 경로(자산/주문/자동매매 등): 미인증 시 페이지는 /login 리다이렉트, API는 401 반환
func Auth(sessionSvc *services.SessionService) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 공개 경로: 인증 없이 통과하되 로그인 상태는 컨텍스트에 저장
if isPublic(r.URL.Path) {
cookie, err := r.Cookie(SessionCookieName)
loggedIn := err == nil && sessionSvc.Validate(cookie.Value)
ctx := context.WithValue(r.Context(), CtxLoggedIn, loggedIn)
next.ServeHTTP(w, r.WithContext(ctx))
return
}
// 쿠키에서 세션 ID 조회
cookie, err := r.Cookie(SessionCookieName)
loggedIn := err == nil && sessionSvc.Validate(cookie.Value)
if !loggedIn {
// API 경로는 401 JSON 반환, 페이지는 /login 리다이렉트
if strings.HasPrefix(r.URL.Path, "/api/") {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(`{"error":"로그인이 필요합니다"}`))
return
}
redirectURL := "/login?next=" + r.URL.RequestURI()
http.Redirect(w, r, redirectURL, http.StatusFound)
return
}
// 로그인 상태를 컨텍스트에 저장
ctx := context.WithValue(r.Context(), CtxLoggedIn, true)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}