사용자 요청 시 권한 처리에 관하여
- 현재 로그인을 통해 액세스 토큰을 받은 사용자는 인증이 필요한 '/auth' 자원에 요청할 수 있다.
의문점
- 회원가입 시 추가적인 정보를 입력받는데 요청 url이 다음과 같다.
- http://localhost:8080/api/auth/account/save/{id}
- 이때 사용자는 부여 받은 액세스 토큰을 함께 전송해야 한다.
- 여기서 나는 다음과 같은 고민을 하였다.
- 가정) 회원가입을 요청하는 사용자의 id가 1인데 값을 2로 하여 서버에 액세스 토큰과 함께 보내면 엉뚱한 사람의 정보가 수정된다는 것이다.
해결방안
해결방안1. @AuthenticationPrincipal 애노테이션으로 권한 처리
- 스프링 시큐리티를 사용하면 컨트롤러 파라미터에서 사용할 수 있는 @AuthenticationPrincipal 애노테이션을 제공해준다.
- @AuthenticationPrincipal 애노테이션은 사용자의로부터 받은 액세스 토큰에서 사용자의 정보를 담은 객체를 가져오는 역할을 한다.
- @AuthenticationPrincipal 애노테이션으로부터 추출한 사용자 id와 url 요청에서의 사용자 id를 비교하여 값이 다르다면 Fobidden Exception을 발생시킨다.
@PostMapping("/save/{id}")
public ResponseEntity<?> completeRegistration(@PathVariable Long id,
@ModelAttribute @Valid SaveAccountRequest saveAccountRequest,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails) throws IOException {
if (id != principalDetails.getAccount().getId()) {
throw new CustomForbiddenException("권한이 없습니다.");
}
ResponseDto responseDto = accountService.saveAdditionalAccountInfo(id, saveAccountRequest);
return new ResponseEntity<>(responseDto, HttpStatus.OK);
}
- 단점
- 추가적인 권한 처리가 발생한다.
- 사용자는 이미 인증을 통해 액세스 토큰을 부여받은 상태이다.
- 그런데 컨트롤러에서 다시 한번 권한 처리를 수행하는 것은 쓸데없는 코드이다.
- 물론 제3자가 사용자의 액세스 토큰을 탈취해 임의로 정보를 바꿀 수 있다.
- 하지만 이러한 문제를 해결하고자 리프래시 토큰을 함께 발급하므로 별 걱정은 하지 않아도 될 것으로 보인다.
- 코드가 깔끔하지 않다.
- 해결방안2와 비교해보면 해결방안1의 코드가 좀 더 복잡한 것을 확인할 수 있다.
- accountService의 saveAdditionalAccountInfo() 메서드를 호출할 때 파라미터로 id를 사용하는데 이 코드는 좋지 못하다.
- 액세스 토큰의 인증 받은 사용자의 id를 두고 url로 받은 id를 사용하는 것은 위험한 방법이다.
- 추가적인 권한 처리가 발생한다.
해결방안2. PrincipalDetails 정보 적극 활용하기
@PostMapping("/save")
public ResponseEntity<?> completeRegistration(@ModelAttribute @Valid SaveAccountRequest saveAccountRequest,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails) throws IOException {
ResponseDto responseDto = accountService.saveAdditionalAccountInfo(principalDetails.getAccount().getId(), saveAccountRequest);
return new ResponseEntity<>(responseDto, HttpStatus.OK);
}
- 확실히 해결방안1에 비해 코드가 깔끔하다.
- 해결방안 1의 단점들을 모두 개선하였다.
- 추가적인 권한 처리를 진행하지 않는다.
- 요청 url과 코드가 확실히 줄어들어 깔끔해졌다.
- PrincipalDetails 객체의 id를 사용해 위험성을 줄였다.
'기술 블로그 > MOLLY' 카테고리의 다른 글
@DataJpaTest (1) | 2023.05.15 |
---|---|
@PatchMapping validation 에러 (0) | 2023.04.30 |
스프링 부트 + 리액트 + JWT + 스프링 시큐리티 + OAUTH2 소셜 로그인 기능 구현 (3) | 2023.04.08 |