feat: 로그인 기능 추가 및 사용자 관리 페이지 전환 구현

Co-authored-by: aider (gemini/gemini-2.5-flash) <aider@aider.chat>
This commit is contained in:
2026-04-13 16:25:16 +09:00
parent 79d1e561d3
commit dcd58a9c53
2 changed files with 154 additions and 6 deletions
+43
View File
@@ -73,6 +73,7 @@ func main() {
// API 엔드포인트
mux.HandleFunc("/api/users", handleUsers)
mux.HandleFunc("/api/users/", handleDeleteUser) // DELETE 요청 처리
mux.HandleFunc("/api/login", handleLogin) // 로그인 요청 처리
log.Printf("VaultKeeper 서버가 %d 포트에서 시작됩니다.\n", appPort)
log.Printf("HTPASSWD_PATH: %s\n", htpasswdPath)
@@ -217,3 +218,45 @@ func handleDeleteUser(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"message": fmt.Sprintf("사용자 '%s'가 성공적으로 삭제되었습니다.", username)})
}
// handleLogin은 사용자 로그인을 처리합니다.
func handleLogin(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "허용되지 않는 메소드입니다.", http.StatusMethodNotAllowed)
return
}
var req LoginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "유효하지 않은 요청 본문입니다.", http.StatusBadRequest)
return
}
// 사용자 이름 유효성 검사 (로그인도 동일하게 적용)
if !usernameRegex.MatchString(req.Username) {
http.Error(w, "유효하지 않은 사용자 이름 형식입니다.", http.StatusBadRequest)
return
}
if req.Username == "" || req.Password == "" {
http.Error(w, "사용자 이름과 비밀번호는 필수입니다.", http.StatusBadRequest)
return
}
htpasswdMutex.Lock()
defer htpasswdMutex.Unlock()
// htpasswd -v <file> <username> <password> 명령어를 사용하여 비밀번호 확인
// exit code 0이면 성공, 0이 아니면 실패
cmd := exec.Command("htpasswd", "-v", htpasswdPath, req.Username, req.Password)
output, err := cmd.CombinedOutput()
if err != nil {
// htpasswd -v는 비밀번호가 일치하지 않거나 사용자 이름을 찾을 수 없으면 에러를 반환합니다.
log.Printf("Login verification failed for user '%s': %v, Output: %s", req.Username, err, output)
http.Error(w, "사용자 이름 또는 비밀번호가 올바르지 않습니다.", http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "로그인 성공"})
}