Skip to content

[Chanyeol] Week8 미션#87

Open
coconutcococode wants to merge 6 commits into
mainfrom
Chanyeol-week8
Open

[Chanyeol] Week8 미션#87
coconutcococode wants to merge 6 commits into
mainfrom
Chanyeol-week8

Conversation

@coconutcococode
Copy link
Copy Markdown
Contributor

@coconutcococode coconutcococode commented May 18, 2026

🔗 연관 이슈

#84

🛠 작업 내용

  • Spring Security 인증/인가 구조 구현
  • CustomAuthenticationProvider 구현
  • 회원가입/로그인 API 구현
  • 인증/인가 실패 응답 통일
  • 도메인 예외 처리 보완
  • SecurityUtil 추가

🖼 스크린샷 (선택)

👀 리뷰 요구사항 (선택)

🤖 AI 활용

  • AI 사용 안 함
  • 코드 작성 아이디어 참고
  • 테스트/리팩토링 보조
  • 문서/주석 작성 보조
  • 기타 (아래에 간단히 작성)

💬 나의 프롬프트

  • SecurityConfig 컴파일 에러 원인이 뭔지 분석해줘
  • 순환 참조 에러 어떻게 해결해?
  • additionalAuthenticationChecks는 어디에 오버라이드해야 해?
  • SecurityContextHolder는 어디서 쓰는 건지 설명해줘
  • 인증/인가 실패 응답을 ApiResponse 형식으로 통일하려면 어떻게 해야 해?
  • 중복 응답 작성 코드를 분리하는 방법이 뭐가 있어?
  • 지금 Filter 폴더를 쓰지 않아도 되는 이유는 뭐야?
  • Writer와 Handler의 차이? 기존 Handler만 쓰는 경우와의 차이?

🧠 AI 응답

  • publicAPI 변수 미선언으로 인한 컴파일 에러 확인 및 /api/** 임시 허용으로 해결 방향 제시
  • PasswordEncoder를 별도 PasswordEncoderConfig로 분리해 순환 참조 해결
  • additionalAuthenticationChecks는 CustomAuthenticationProvider에 오버라이드해야 한다고 안내
  • SecurityUtil.getCurrentMemberId() 패턴 제안
  • CustomAuthenticationEntryPoint, CustomAccessDeniedHandler, 성공/실패 핸들러 구조 제안
  • 중복 응답 작성 코드는 util보다 SecurityResponseWriter 같은 writer 컴포넌트로 분리하는 것이 책임 분리 측면에서 적절하다고 설명
  • 현재 프로젝트 구조는 Spring Security의 기본 필터 체인을 그대로 활용하면서 커스텀 컴포넌트로 동작을 오버라이딩하는 방식 -> JWT를 도입한다면 필요하겠지만 이미 현재 방식으로도 요구사항을 충족하다고 설명
  • Handler: 언제 응답할지 결정, Writer: 어떤 JSON 형태로 응답할지 작성, new ObjectMapper() 반복 제거는 부수 효과, 핵심은 중복 제거와 책임 분리

✅ 내가 최종 선택한 방법 (이유)

  • publicAPI 변수 선언 추가로 컴파일 에러 해결: 이후 /api/** 임시 허용은 인증 구현 완료 후 제거
  • PasswordEncoderConfig 분리로 순환 참조 해결: 구조적으로 깔끔하고 Spring 권장 방식이기 때문
  • CustomAuthenticationProvider에 additionalAuthenticationChecks 오버라이드: 인증 로직은 Provider에서 관리하는 것이 책임 분리에 맞기 때문
  • SecurityUtil.getCurrentMemberId() 도입: 하드코딩 제거와 Security 컨텍스트 접근을 일관된 방식으로 관리하기 위해 채택
  • CustomAuthenticationEntryPoint, CustomAccessDeniedHandler, 성공/실패 핸들러 구현: 모든 실패 응답을 ApiResponse 형식으로 통일하기 위해 채택
  • 응답 작성 로직을 SecurityResponseWriter로 분리: 이후 응답 형식 변경 시 한 곳만 수정하면 되므로 유지보수 측면에서 채택
  • 그대로 Spring Security의 formLogin() + 커스텀 핸들러/프로바이더 조합으로 유지: 9주차에 JWT에 대해 배우게 되면 그때 진행하기로 결정

💡 나만의 Tip (선택)

@coconutcococode coconutcococode self-assigned this May 18, 2026
@coconutcococode coconutcococode linked an issue May 18, 2026 that may be closed by this pull request
4 tasks
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f029fed07

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authenticationProvider(customAuthenticationProvider)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 세션 로그인에서 CSRF 보호를 비활성화하지 마세요

현재 설정은 formLogin으로 세션 기반 인증을 사용하면서 CSRF를 전역 비활성화하고 있어, 브라우저 쿠키(JSESSIONID)가 자동 전송되는 환경에서는 사용자가 의도하지 않은 상태 변경 요청이 통과할 수 있습니다. Spring Security 학습 관점에서도 “세션 기반이면 CSRF 기본값 유지, stateless 토큰 기반이면 비활성화”를 구분하는 습관이 중요하므로, CSRF를 유지하고 필요한 엔드포인트만 예외 처리하거나 인증 방식을 stateless로 명확히 전환해보는 것이 좋습니다.

Useful? React with 👍 / 👎.

Comment on lines +48 to +49
.loginProcessingUrl("/auth/login")
.usernameParameter("email")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge JSON 로그인 요청도 처리되게 인증 입력 방식을 맞추세요

현재 /auth/loginformLoginUsernamePasswordAuthenticationFilter 경로만 사용하므로, 클라이언트가 JSON 본문({"email":...,"password":...})으로 로그인하면 자격 증명을 읽지 못해 항상 인증 실패가 납니다. 이 레포가 @RequestBody 기반 API 스타일을 주로 쓰는 점을 고려하면, 로그인 요청 포맷을 application/x-www-form-urlencoded로 명확히 고정해 문서화하거나, AuthenticationManager를 쓰는 로그인 컨트롤러/커스텀 필터를 추가해 JSON 로그인을 지원하는 쪽으로 정리하는 것이 학습적으로도 좋습니다.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@kjhh2605 kjhh2605 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[키워드 조사]
Spring Security의 필터 체인, 인증/인가, Stateful/Stateless 흐름을 핵심 키워드로 정리한 점이 좋습니다. 다만 인증(Authentication)과 인가(Authorization)의 용어 경계, 세션 기반 로그인과 JWT 기반 인증의 설정 차이를 코드와 연결해 보완하는 것을 권장합니다. 특히 현재 구현은 form login과 세션 흐름에 가까우므로, REST API에서 JSON 응답을 유지할 때 필요한 설정과 JWT를 사용할 때 달라지는 구성을 비교해 정리하면 학습 효과가 높아집니다.

[코드 리뷰]
SecurityFilterChain, PasswordEncoder, UserDetailsService, 인증 성공/실패 핸들러를 직접 구성하여 Spring Security의 주요 확장 지점을 경험한 점이 좋습니다. 회원가입에서 비밀번호를 BCrypt로 저장하고, 로그인 실패/인가 실패 응답을 공통 ApiResponse 형식으로 맞추려는 방향도 적절합니다. 추가로 CSRF/세션 정책, SecurityContext 조회 실패 예외, 회원가입 입력 검증 책임을 명확히 하면 인증 흐름의 안정성과 계층 책임 분리가 더 좋아집니다.

![스크린샷 2026-05-18 오후 1.55.14.png](attachment:bb447443-1268-43fd-8edb-041dc7f1dfe0:스크린샷_2026-05-18_오후_1.55.14.png)

- 인증(Authentication) : 본인이누구인지확인 (로그인)
- 승인(Authorization) : 특정 리소스에권한이 있는지확인 (등급 권한)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Authorization은 일반적으로 ‘승인’보다 ‘인가’로 번역하는 것이 적절합니다. 인증은 사용자가 누구인지 확인하는 과정이고, 인가는 인증된 사용자가 특정 리소스나 행위를 수행할 권한이 있는지 확인하는 과정으로 구분해 정리하는 것을 권장합니다.

public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authenticationProvider(customAuthenticationProvider)
.csrf(AbstractHttpConfigurer::disable)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSRF를 비활성화하는 선택은 REST API나 Stateless 인증 전략에서는 자주 사용되지만, 현재 설정은 formLogin과 세션 기반 흐름에 가깝습니다. 학습 관점에서는 ‘세션 기반 form login에서는 CSRF를 어떻게 둘지’, ‘JWT 기반 API에서는 왜 끄는지’를 주석이나 설정으로 구분해 두는 것을 권장합니다.

return MemberConverter.toSignUpRes(member);
}

private LocalDate parseBirthday(String birthday) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생년월일·성별 형식 검증을 Service에서 보완한 점은 좋습니다. 다음 단계에서는 @Pattern, enum 전용 요청 타입, 커스텀 Validator 중 어떤 방식이 Controller 진입 전 입력 계약을 더 명확히 표현하는지 비교해 보는 것을 권장합니다.


if (authentication == null || !(authentication.getPrincipal() instanceof AuthMember
authMember)) {
throw new RuntimeException("로그인 정보가 없습니다.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인증 정보가 없을 때 RuntimeException을 직접 던지면 공통 예외 응답 코드와 연결하기 어렵습니다. 이미 도메인/공통 예외 구조를 사용하고 있으므로, 인증 실패 상황도 커스텀 예외나 공통 에러 코드로 연결하는 것을 권장합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 8주차-Spring Security - Security 구조, 폼 로그인

2 participants