늦은 프로그래밍 이야기
230102 TIL 본문
팀프로젝트
Spring Security
admin 회원가입이 되지 않는 문제
저번주 작성한 프로젝트의 회원가입 부분에서 admin 계정의 회원가입이 되지 않는 문제가 확인이 되었다. UsernamePasswordAuthenticationFilter : An internal error occurred while trying to authenticate the user. 이라는 에러메시지와 InternalAuthenticationServiceException: 사용자를 찾을 수 없습니다. 라는 예외 문구가 출력되었다. UserDetailsServiceImpl에서 발생하는 예외인 것 같은데 일반유저 회원가입 때는 발생하지 않는 에러이니 adminToken과 관련해서 발생하는 에러 같다.
http.formLogin().loginProcessingUrl("/login").permitAll();
기본 시큐리티 로그인 폼을 불러오는 코드를 제거하고 실행해 보았다. 상태코드를 반환하지 못하고 아무 반응도 없고 아무런 에러도 발생하지 않는다.
차근차근 문제를 찾아가던 중, 일반유저의 회원가입 url과 로그인 url은 permitAll()을 해줬는데 어드민 회원가입 url은 permitAll을 하지 않은 것을 발견하고, 어드민 회원가입 url도 permitAll을 작성하였다.
WebSecurityConfig CLASS
http.authorizeHttpRequests().antMatchers("/users/signup").permitAll()
.antMatchers("/admin/signup").permitAll()
.antMatchers("/users/login").permitAll()
.anyRequest().authenticated()
.and().addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
의외로 간단한 문제였지만, 에러메시지와 예외문구가 쉽게 예상하지 못하게 출력되어서 꽤나 해결하는데 오래걸렸다. 디버깅이 안되는 것을 보고 permitAll을 하지 않고 인증이 되지 않으면 url에 접근조차 하지 않는 것을 알게 되었다.
게시글 조회가 되지 않는 문제
게시글 조회 기능을 postman에서 확인해보면 기본 시큐리티 로그인 페이지의 html 코드가 출력되는 현상이 발생했다. 이번에도 스프링 시큐리티 기본 로그인 페이지 코드를 제거하고 실행을 시켜보면 아무것도 출력되지 않고 반환하지 않는 것을 확인했다.
WebSecurityConfig CLASS
http.authorizeHttpRequests().antMatchers("/users/signup").permitAll()
.antMatchers("/admin/signup").permitAll()
.antMatchers("/users/login").permitAll()
.antMatchers("/posts").permitAll()
.andMatchers("/posts/id").permitAll()
.anyRequest().authenticated()
.and().addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
위와 같은 문제라고 생각되서 게시글 조회 url을 permitAll() 해줬더니 조회가 되었지만, 이렇게 작성하게 되면 게시글 작성 url과 게시글 조회 url이 동일하기 때문에 게시글 작성 기능에도 인증 / 인가 없이 작성이 가능하게 되어 url의 변경을 고려 해봐야 한다.
그리고 또 하나의 문제는 게시글 조회를 permitAll 해줘야 하는지는 고민을 해보아야 할 것이다. 모두가 조회를 할 수 있다면 permitAll을 해줘도 되지만, 로그인 한 사용자만 게시글 조회가 가능하게 하려면 인증 / 인가를 통해 확인된 사용자만 게시글을 조회할 수 있게 해야할 것이다.
이건 일단 두가지 방법이 있다는 것을 알고만 있고 정보를 더 얻거나 팀원들과 회의를 통해서 결정하고 진행해야 할 것이다.
User 회원가입에 작성한 정규표현식이 적용이 안되는 문제
UserSignupRequestDto에 username과 password에 어노테이션으로 작성한 정규표현식이 적용이 되지 않았다. 정규표현식 자체는 문제가 없었고, @Pattern 어노테이션과 @Size 어노테이션을 달아줘서 동작을 하는 것을 개인과제 할 때 확인을 했었는데 적용이 안되서 당황했지만, 차근히 한번 찾아보았다.
UserContoller CLASS
@PostMapping("/users/signup")
public ResponseEntity<StatusResponseDto> signup (@RequestBody @Valid UserSignupRequestDto requestDto) {
StatusResponseDto responseDto = new StatusResponseDto(HttpStatus.CREATED.value(), "회원가입 완료");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
userService.signup(requestDto);
return new ResponseEntity<>(responseDto, headers, HttpStatus.CREATED);
시큐리티를 적용해서 안되는 건지 User 엔티티에 작성을 해야 되는건지 생각하던 중 UserController의 signup 메소드의 파라미터를 보니 @Valid 어노테이션이 누락된 것을 확인하였다. 거의 바로 찾을 수 있었다. 다음부터는 이런 사소한 실수는 하지 않도록 해야겠다.
Merge 후 실행이 되지 않는 문제
오늘 기본적인 기능들을 모두 구현하고 2번째 merge를 하였는데 실행이 되지 않았다. UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL이라고 에러 문구가 출력되고 to {PUT [/post/{postId}/comments/{commentId}]}: There is already 'commentController' bean method 이라고 힌트까지 줘서 PUT 메소드 쪽을 유심히 살펴 보았다.
UnsatisfiedDependencyException은 지난번에 한번 겪어봤던 에러였는데 그때는 repository의 메소드가 잘못 되어서 나왔었는데 이번에는 URL이 잘못 되어서 나온 에러였다.
@PutMapping("/posts/{postId}/comments/{commentId}")
@PutMapping("/admin/posts/{postId}/comments/{commentId}")
@DeleteMapping("/posts/{postId}/comments/{commentId}")
@DeleteMapping("/admin/post/{postId}/comments/{commentId}")
PUT과 DELETE 메소드는 admin 메소드가 따로 있는데 그 URL에 /admin을 누락하여서 일반회원의 PUT과 DELETE의 URL과 중복이 되어 발생하는 에러였다. URL에 admin을 입력해주니 실행이 되지 않던 오류가 해결되었다. 에러를 만날 때 기록해두는 습관 덕에 찾아보지 않고도 기록에 두는 것 만으로 기억이 잘 나는 것 같다.
@Secured
개인과제로 혼자 스프링 시큐리티를 리팩토링 하면서 admin 권한이 있는 기능을 리팩토링 하면서 기존에 작성하였던 isAdmin 메소드를 다시 사용했는데 스프링 시큐리티가 admin 여부를 체크해서 어노테이션 하나로 admin 권한을 체크할 수 있는 기능을 강의에서 배웠던게 생각나서 @Secured 어노테이션으로 다시 적용을 하였다.
AS-IS
@PutMapping("/admin/posts/{postId}/comments/{id}")
public CommentResponseDto updateCommentAdmin(@PathVariable Long id, @RequestBody CommentRequestDto requestDto, @HttpServletRequest request) {
String token = jwtUtil.resolveToken(request);
if (token == null) {
throw new IllegalArgumentException("토큰이 유효하지 않습니다.");
}
AuthenticatedUserInfoDto authenticatedUserInfoDto = jwtUtil.validateAndGetUserInfo(token);
if (!this.isAdmin(authenticatedUserInfoDto.getUserRoleEnum())) {
throw new IllegalArgumentException("권한이 없습니다.");
}
TO-BE
@PutMapping("/admin/posts/{postId}/comments/{id}")
@Secured(UserRoleEnum.Authority.ADMIN)
public ResponseEntity<StatusResponseDto> deleteCommentAdmin(@PathVariable Long id, @AuthenticationPrincipal UserDetails userDetails) {
return commentService.updateAdmin(id, requestDto);
}
'내일배움캠프 > TIL, WIL' 카테고리의 다른 글
| 230104 TIL (계층형 카테고리) (0) | 2023.01.05 |
|---|---|
| 230103 TIL (0) | 2023.01.04 |
| 9주차 WIL (0) | 2023.01.01 |
| 221230 TIL (Git, 팀프로젝트) (0) | 2022.12.31 |
| 221229 TIL (0) | 2022.12.30 |