[Hyeonu] Week8 미션#85
Conversation
kjhh2605
left a comment
There was a problem hiding this comment.
[키워드 조사]
Spring Security의 인증/인가, Filter Chain, Stateful/Stateless 흐름을 이번 미션 코드와 함께 연결하려는 방향이 좋습니다. 다만 Stateful의 장단점과 Stateless의 장단점이 일부 섞여 있어, 세션 기반 인증과 JWT 기반 인증에서 서버가 저장하는 정보, 로그아웃 처리 방식, 토큰 탈취 위험을 기준으로 다시 구분하는 것을 권장합니다. 추가로 PasswordEncoder, UserDetailsService, SecurityFilterChain, AuthenticationEntryPoint와 AccessDeniedHandler가 요청 흐름에서 언제 호출되는지 순서도로 정리하면 이해가 더 명확해집니다.
[코드 리뷰]
계층 구조를 유지하면서 회원가입, 인증 설정, 예외 응답, 미션/리뷰 조회 기능을 확장한 점이 좋습니다. 특히 도메인별 성공 코드와 Security 예외 핸들러를 분리하려는 시도는 응답 일관성을 높이는 방향입니다. 보완할 부분은 인증을 도입한 뒤에도 클라이언트가 memberId를 직접 전달하는 API가 남아 있는 점, 요청 DTO 검증과 중복 이메일 검사가 부족한 점, 빈 페이지에서 커서 계산이 실패할 수 있는 점입니다. 이번 주차에서는 “인증된 사용자 정보는 어디에서 가져와야 하는가”, “DTO 검증은 Controller 진입 시점에서 어떻게 보장하는가”, “Slice 기반 페이지네이션에서 빈 결과와 마지막 페이지를 어떻게 표현하는가”를 함께 점검하는 것을 권장합니다.
| @PostMapping("/v1/members/me") | ||
| public ResponseEntity<ApiResponse<MemberResDTO.GetInfo>> getInfo( | ||
| // 받은 JSON 데이터를 자바 객체(dto)로 변환해서 씀 | ||
| @RequestBody MemberReqDTO.GetInfo dto |
There was a problem hiding this comment.
Spring Security를 도입한 뒤 /members/me API에서 memberId를 요청 바디로 받으면 다른 사용자의 ID를 넣어 조회할 수 있는 구조가 됩니다. @AuthenticationPrincipal 또는 SecurityContext에서 인증된 사용자를 가져오도록 바꾸면 인증 계층과 회원 조회 유스케이스의 책임이 더 명확해집니다.
| String detailAddress, | ||
| String phoneNumber, | ||
| String email, | ||
| String password |
There was a problem hiding this comment.
회원가입 요청 DTO에 비밀번호, 이메일, 이름 같은 필수 입력값 검증이 아직 보이지 않습니다. @NotBlank, @Email, 길이 제한 등을 DTO에 선언하고 Controller에서 @Valid를 적용하면 잘못된 입력이 Service 계층까지 내려가지 않아 계층 책임이 더 분명해집니다.
| missionList=missionRepository.findMissionByStore_IdOrderByIdDesc(storeId,pageRequest); | ||
| } | ||
| // 다음 커서 계산 | ||
| nextCursor=missionList.getContent().getLast().getId()+":"+missionList.getContent().getLast().getId(); |
There was a problem hiding this comment.
조회 결과가 비어 있으면 getLast() 호출에서 예외가 발생할 수 있습니다. reviewList에서 처리한 것처럼 hasNext()와 getContent().isEmpty()를 함께 확인하고, 마지막 페이지나 빈 결과에서는 nextCursor를 null로 내려주는 흐름을 권장합니다.
| .anyRequest().authenticated() // 그 외 모든 요청은 로그인 필요 | ||
| ) | ||
| // 폼 로그인 설정 | ||
| .formLogin(form -> form |
There was a problem hiding this comment.
현재 설정은 REST API 응답을 JSON으로 통일하면서도 formLogin의 기본 세션 로그인 흐름을 함께 사용합니다. 이번 주차 목표가 Stateful 세션 방식인지, JWT 기반 Stateless 방식인지 먼저 정하고 그에 맞춰 로그인 성공/실패 응답, 세션 정책, CSRF 설정을 함께 정리하는 것을 권장합니다.
|
|
||
| 장점 | ||
|
|
||
| 토큰 탈취 시 만료 전까지 막기 어려움 |
There was a problem hiding this comment.
토큰 탈취 시 만료 전까지 막기 어려움은 JWT 방식의 장점보다 단점에 가깝습니다. Stateless의 장점은 서버 확장성과 세션 저장소 의존성 감소로 정리하고, 토큰 탈취 위험과 즉시 로그아웃의 어려움은 단점으로 분리하면 개념 구분이 더 정확해집니다.
| @Query("SELECT m FROM Member m WHERE m.name=:name AND m.deletedAt IS NULL") | ||
| Optional<Member> findActiveMember(String name); | ||
|
|
||
| Optional<Member> findByEmail(String username); |
There was a problem hiding this comment.
메소드 시그니처와 전달받는 매개변수의 이름이 명확히 구분되지 않습니다.
🔗 연관 이슈
closes #83
🛠 작업 내용
Spring Security 의존성 추가
SecurityConfig 설정 (CSRF 비활성화, Public/Private API 분리, 폼 로그인/로그아웃)
AuthMember, CustomUserDetailsService 구현
CustomEntryPoint(401), CustomAccessDenied(403) 구현으로 인증/인가 실패 응답 통일
회원가입 API 구현 (/api/auth/sign-up, BCrypt 비밀번호 암호화)
코드 정리 (MemberSuccessCode 통합, 미사용 import 제거)
🖼 스크린샷 (선택)
👀 리뷰 요구사항 (선택)
🤖 AI 활용
💬 나의 프롬프트
회원가입할때 여러 정보들을 받는데 왜 비밀번호만 가지고 암호화해서 다뤄 다른건 안다뤄? 비밀번호만 따로 처리를해주고 나머지는 그냥 받으면되서 나머진 컨버터에서 해주는건가
🧠 AI 응답
나머지 필드들(name, gender, birth 등)은 그냥 받은 값 그대로 DB에 저장하면 되는데, password만 BCrypt 암호화라는 추가 처리가 필요하기 때문에 Service에서 먼저 처리 후 Converter로 전달
✅ 내가 최종 선택한 방법 (이유)
비밀번호만 따로 처리가 필요한 정보라는 것을 납득했다.
💡 나만의 Tip (선택)