어제 Spring Security 도입을 마무리 하고, 다음 단계를 진행하다가 일정을 생성하는 부분에서 다음과 같이 NPE가 발생했다.
Postman에서는 403 Forbidden 에러가 난 상황이다.
회원가입과 로그인은 정상적으로 됐고, DB에도 모든 정보가 다 빠짐없이 들어있다.
왜 userRole이 null인가...🤔 DB에도 다 들어있는데 왜 null이지...?
이 상황을 믿을 수가 없어 생성자에서 userRole이 null일 때 에러를 던지도록 해 다시 한 번 확인해봤다.
null이 맞다. 그렇다면 왜일까?
검색의 늪에 빠져있다가 여러 상황을 가정하고 확인해보았다.
userRole
을 다른 단어로 입력한 경우userRole
로 같음.userRole
이 포함되지 않은 경우JwtAuthenticationFilter
에서 setAuthentication()
을 보면 다음과 같다. 여기서 해당 메서드는 JWT 토큰을 검증한 후, Spring Security의 SecurityContext에 인증된 사용자 정보를 저장하는 역할을 한다. 여기서 JwtAuthenticationToken
부분을 보면 Spring Security에서 사용할 Authentication 객체를 생성한다.
JwtAuthenticationToken
클래스로 가서 다시 한 번 살펴보니 사용자의 권한(userRole
)을 설정하고, 인증된 사용자로 set한다. 그리고 맨 아래 getPrincipal()
메서드를 통해 현재 로그인한 사용자의 정보를 반환한다. 여기서 이 getPrincipal()
메서드를 사용하고 있지 않다는 것을 깨달았다.
따라서 나는 이 부분을 이용해야 한다는 생각이 들어 TodoController
의 saveTodo()
메서드에서 @Auth
어노테이션을 주석 처리한 후, 직접 getPrincipal()
메서드를 불러 authUser
에 넣고 테스트 해봤다.
드디어 제대로 일정이 생성되었다! 하지만 @Auth
를 이용해 바꿔야 했는데, 이 부분에서 내가 어제 실수를 했다는 것을 알게되었다.
바로 파일 정리를 하다가 생각없이 AuthUserArgumentResolver
와 WebConfig
를 삭제해버린 것이다.... 이 부분은 삭제하지 말고 Spring Security로 변경했어야 했는데, 필요없다고 생각해서 지웠다. 차라리 지우지 않았더라면 더 빨리 해결할 수 있었을 텐데 말이다. 정확한 이해 없이 적용하려고만 해서 이런 일이 벌어진 것 같다.😓
따라서 다시 해당 파일을 만든 후, AuthUserArgumentResolver
의 resolveArgument()
메서드를 다음과 같이 수정했다. 이전에는 값을 request에서 하나씩 가져와 새로운 AuthUser 객체를 만들어 반환했다.
수정 후, 현재 인증된 사용자의 정보를 가져와서(SecurityContextHolder.getContext().getAuthentication()
) Principal을 꺼내(getPrincipal()
) AuthUser로 반환한다. 이렇게 반환된 AuthUser는 TodoController
의 authUser
파라미터에 자동으로 들어간다.
따라서 기존과 같이 이렇게 적어줘도 이제 정상적으로 들어간다.
Postman에서도 잘 테스트 된다.
자, 이렇게 겨우겨우 에러를 해결했지만 이 방법을 아래 어노테이션 하나로 해결할 수 있었다.
@AuthenticationPrincipal
'
이렇게 바꾸면 바로 적용 가능하다.
...나 오늘 뭐한거지...?🙄 팀원 분이 마지막 스크럼때 알려주셔서 알았다. 강의를 더 자세히 봐야한다는 교훈을 얻었다. 강의 다시 봐야지...