20221218- 회고

선을로·2022년 12월 18일
0

회고

목록 보기
9/20

학습회고

며칠동안 시큐리티 폼 로그인 구현하면서 많이 헤맸다.

WARN 9936 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'singleproject.bulletinboard.config.auth.dto.SessionUser' to required type 'singleproject.bulletinboard.domain.user.Member'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'singleproject.bulletinboard.config.auth.dto.SessionUser' to required type 'singleproject.bulletinboard.domain.user.Member': no matching editors or conversion strategy found]

저번에 도메인 객체를 Session에 등록하기전에 직렬화 Dto로 타입변환을 해서 등록했는데,
이번에 발생한 오류에서 변환을 못했다길래
새로 코드를 짜서 디버깅으로 정말 변환 못하나 실험해봤는데
타입변환은 잘되네?
문제는 그것을 세션에 등록하고 이어지는 동작 중에
시큐리티 관련해서 뭔가 문제가 있는 것인지
전혀 상관없는 저 오류를 내뱉는다.

어디서 타입변환을 문제 삼는건지 궁금해서
디버깅으로 쫒아가봤으나...너무 깊어서 몇분간 타고들어가도 원인을 알아내기 힘들었다.

OAuth2 소셜 로그인 자체는 문제없이 돌아가는데
Form 로그인만 문제다.

시큐리티 설정에서 폼 로그인에서 문제 발생 시 예외처리에 대한 내용도 추가했다.

.formLogin()
.loginPage("/user/login")
.usernameParameter("name")
.passwordParameter("password")
.loginProcessingUrl("/authenticate")
.defaultSuccessUrl("/board", true)
.successHandler(
new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("authentication : " + authentication.getName());
response.sendRedirect("/");
}
}
)
.failureHandler(
new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
System.out.println("exception : " + exception.getMessage());
response.sendRedirect("/login");
}
}
)
.permitAll()

failureHandler에서 Exception내용을 뱉었는데 뭐였는 지 기록하는건 깜빡함😅
여튼 그걸로도 정확한 원인을 찾을 수 없었다.

그래서 생각하고 생각하고 또 생각하고 실험해보면서 문득

"세션등록이 문제라면 세션등록을 생략해보자!"

컨트롤러에서 세션등록하는 코드를 주석처리하고,
다시 실험해보니
이제는 문제없이 successHandler가 로그인이 되었다고 한다.

근데 세션에 회원정보를 등록하는 코드는 지웠으니
당연히 세션에서는 아무것도 꺼낼 수 없었다.

Dto를 세션에 등록하려하면 로그인이 안되고,
Dto를 세션에 등록 안하면 로그인이 되는 딜레마에 빠져서 허우적대다가

그러고보니 내가 시큐리티를 제대로 공부하긴 한걸까?
책에 나와있는 내용은 꼼꼼히 읽었지만,
알고보니 책에서는 OAuth2소셜 로그인 방법만 알려줄 뿐
Form 로그인에 대해서는 언급도 없고
시큐리티에 대한 상세한 내용도 없었다.

결국 시큐리티에 대해 구글링 하면서 살펴보았으나
내가 원하는 내용만 콕 찝어 찾기엔
시큐리티에 대한 설명이 너무 방대해보였다.

이래선 '모래사장에 바늘찾기'꼴이 될거 같아서
좀 더 생각한 끝에 발상의 전환을 해보았다.

"시큐리티가 자기입으로 로그인이 성공했다고 했으니
분명 로그인한 유저의 데이터도 지니고 있지 않을까?
세션에 굳이 유저정보를 등록할 필요가 없이 꺼내올 수 있는 방법이 있지 않을까?"

를 주제로 삼고 다시 시큐리티에 대한 원리를 구글링해보니
UserDetails와 UserDetailsService라는 존재를 알 수 있었다.
시큐리티에서 사용자의 정보를 불러오기 위해 구현해야 하는 인터페이스였기에 구현체를 만들었고,
SecurityContextHolder에서 SecurityContext-> authentication -> principal 에 접근해서 로그인 정보를 가져오거나,
세션을 통해 SecurityContext객체를 가져와서 마찬가지로 principal 까지 접근해서 로그인 정보를 가져오는 방식을 찾을 수 있었다.😂 🏥산소호흡기🏥

아아..구글링 하면서 훑고 지나간 'SecurityContext가 있고 여기에 로그인한 유저의 권한 정보를 담는다'는게 이런 뜻이었구나.
SecurityContext는 Session에도 저장되어 전역적으로 SecurityContext를 참조할 수 있다한다.

분명 몇번 훑어보고도 제대로 이해하지 못한 채 지나간 내용들인거 같긴한데,
필요한 문제가 생기면 꼭 눈에 들어오더라..😥

기술 원리 공부에 대한 중요성을 체감한 것 같다.

되새김

0개의 댓글