Skip to content

[ASSIGNMENT] 6차 과제 - #20

Open
laura-jung wants to merge 13 commits into
mainfrom
assignment/#19/assignment6
Open

[ASSIGNMENT] 6차 과제#20
laura-jung wants to merge 13 commits into
mainfrom
assignment/#19/assignment6

Conversation

@laura-jung

@laura-jung laura-jung commented May 21, 2026

Copy link
Copy Markdown
Collaborator

🔥Pull requests

👷 과제 구현

필수과제

  • JWT + Spring Security 인증을 에브리타임 클론 프로젝트 전체에 적용해주세요. 로그인/토큰 재발급 API는 인증 없이 접근 가능하고, 게시글 작성/수정/삭제, 좋아요 추가/취소는 인증이 필요하도록 설정해주세요.
  • 비밀번호를 평문으로 저장하는 건 위험해요. BCryptPasswordEncoder를 사용해서 비밀번호를 암호화해서 저장하고, 로그인 시 matches()로 검증하도록 수정해주세요.

선택과제

  • 로그아웃 API를 구현해주세요. 로그아웃 시 DB에서 해당 유저의 Refresh Token을 삭제하고, 현재 Access Token을 블랙리스트에 추가해서 만료 전에도 사용할 수 없도록 해주세요. Access Token이 만료됐을 때 클라이언트가 어떻게 401을 감지해서 로그인 페이지로 이동시킬지 흐름도 함께 작성해주세요.
  • Kakao 또는 Google OAuth 2.0 소셜 로그인을 구현해주세요. 외부 인증 서버로부터 유저 정보를 받아온 후, 우리 서버에서 JWT(Access Token + Refresh Token)를 발급하는 흐름까지 완성해주세요. 신규 유저라면 자동으로 회원가입 처리하고, 기존 유저라면 로그인 처리해주세요.

구현한 내용에 대해서 설명해주세요

  • JWT + Spring Security 인증을 에브리 타임 클론 프로젝트 전체에 적용하였습니다.
    기존 JWTFIlter가 principal 값을 string으로 변환하는 것을 수정하여 id값 그대로 내려올 수 있게하였고, 이후 controller에서 AuthenticationPrincipal을 사용하여 토큰정보로 부터 id 값을 바로 불러올 수 있도록 하였습니다.
  • 로그인, 토큰 재발급, 유저 생성의 경우에는 인증 없이 접근 가능하도록 securityConfig를 수정하였습니다.
  • 게시글 작성, 수정, 삭제, 좋아요 추가, 취소는 인증이 필요하도록 controller에 추가하였고, securityConfig에도 한번더 추가하였습니다.
  • 비밀번호를 암호화해서 저장하고 로그인시 matches로 검증하도록 하였습니다.
  • 추가로 기존에 user 정보가 일치 하지 않을 경우 커스텀 예외처리를 통해 처리하도록 하였는데 JWTFilter를 도입하면서 filter 단에서 미리 에러처리가 이루어져서 에러 메세지가 제대로 보이지 않는 이슈가 있었습니다. 이를 해결하기 위해 CustomAuthenticationEntryPoint를 구현하여 기존 에러 응답구조와 동일하게 응답할 수 있도록 하였습니다.

아래는 postman 스크린샷입니다.
스크린샷 2026-05-22 오전 2 35 56
스크린샷 2026-05-22 오전 2 37 34


구현하며 고민했던 내용을 적어주세요 (사소한 것도 좋아요)

  • 이전에 진행했던 프로젝트들에서는 모두 AuthenticationPrincipal을 사용하여 이용자의 id를 불러왔어서 이번 과제에서도 그렇게 수정했는데요.... 이게 맞는 방법이 맞는지에 대한 생각이드네요.... principal에서 string 값을 쓸일이 없을 것 같다는 생각이 들어 id 값 그대로 반환할 수 있도록 수정하였습니다. 더 좋은 방법이나 이렇게 하면 안되는 이유가 있다면 리뷰 부탁드립니다.
  • 실은 제가 가장 약한 부분이 spring security, jwt인데요.....빠진 부분이나 미흡한 부분이 있다면 많은 리뷰 부탁드립니다.
  • 그리고 요즘들어 커밋 쪼개기가 너무 힘든데 잘 쪼개는 방법이 있나요....?


키워드 과제 정리내용

https://picayune-neon-796.notion.site/7-368d0ccedfad805fa951ee361fc2a2fc?source=copy_link



🚨 참고 사항

  • 심화 과제 반드시 일요일 전까지 해놓을게요.....

@laura-jung laura-jung linked an issue May 21, 2026 that may be closed by this pull request
@laura-jung laura-jung self-assigned this May 21, 2026

if (!user.getPassword().equals(password)) {
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new IllegalArgumentException("이메일 또는 비밀번호가 올바르지 않습니다.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

계정 관련된 에러는 AuthErrorCode같은것을 추가해서 CustomException으로 받아줘도 좋을 것 같아요!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

네 수정하겠습니다!

@Tag(name = "Post", description = "게시글 api")
@RestController
@RequiredArgsConstructor
@RequestMapping("api/v1/posts")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

저도 이전에 실수로 빼먹었던 사례인데 잘 찾아서 정리하셨네요! 저는 피드백 받고 수정을 했는데 눈썰미가 좋으시네요

public ResponseEntity<BaseResponse<TokenResponse>> login(
@RequestParam("email") String email,
@RequestParam("password") String password
@RequestBody LoginRequest request

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

DTO로 변환해서 Body로 받으니까 더 깔끔하고 좋은 것 같아요!

Comment on lines 32 to 36
.orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND));

Post post = new Post(request.title(), request.content(), user);
postRepository.save(post); // 영속성 컨텍스트에 올라감
postRepository.save(post);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CustomException을 통해 코드를 줄이는 방법 좋은 것 같아요!

this.password = password;
}

public static User create(String nickname, String email, String encodedPassword) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

정적 패토리메서드 는 대부분 of, from을 봤는데 엔티티를 만드는 user는 create라 좋은 것 같네요

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

정적 메서드는 이름을 통해 사용법을 구별하는게 좋다고 하더라고요!

@guswnsj0112

Copy link
Copy Markdown

과제하느라 고생 많으셨습니다!!!

@imddoy imddoy left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

짱짱 수고하셨습니당~~~~

throw new IllegalArgumentException("인증되지 않았습니다.");
@GetMapping("/me")
public ResponseEntity<BaseResponse<UserResponse>> me(
@AuthenticationPrincipal Long userId

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

오호 이렇게 어노테이션을 달면 중복이 줄어드는군요!! 저도 공부해보겠습니당


Long memberId = jwtService.verifyAndGetMemberId(refreshToken);
User user = userRepository.findById(memberId)
.orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다."));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이 부분은 비즈니스 에러로 커스텀 해도 좋을 것 같아요!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

네 수정하겠습니다!

Long memberId = jwtService.verifyAndGetMemberId(token);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
String.valueOf(memberId), null, Collections.emptyList());
memberId, null, Collections.emptyList());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이 부분 object라 String 안하고 그냥 해도 된다구 하더라구요 전 변환해주고 있었는데 역시 꼼꼼하시네용!!

Post post = postRepository.findById(id)
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));

if (!post.getUser().getId().equals(userId)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

중복 로직인데 메서드로 빼도 괜찮지 않을까요???

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

오 그래도 좋을 것 같네요! 반영하겠습니다!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ASSIGNMENT] 6차 과제 구현

4 participants