@AuthenticationPrincipal에 null값 들어오는 문제

이민우·2023년 11월 6일
2

모두의 마당 프로젝트에서 OAuth2 기반 네이버, 구글 소셜 로그인 구현 중, @AuthenticationPrincipal에 null값 들어오는 문제가 생겼다.

세션 기반 로그인 인증 방법을 사용했는데, 로그인한 유저가 세션에 저장되지 않는 오류같앴다.

참고
@AuthenticationPrincipal이란!
세션 정보 UserDetails에 접근할 수 있는 어노테이션

OAuth2 로그인 과정:

  1. Authorization Request
    사용자가 어플리케이션에 로그인 요청을 하면, 어플리케이션은 사용자를 OAuth2 제공자의 인증 서버로 리다이렉트합니다. 이 때, 사용자의 동의를 얻기 위해 필요한 정보(예: 사용자 프로필, 이메일 등)에 대한 권한을 요청합니다.
  2. User Approval
    사용자는 OAuth2 제공자의 페이지에서 해당 권한을 승인하게 됩니다.
  3. Authorization Grant
    사용자가 권한을 승인하면, OAuth2 제공자는 'code'라는 인증 코드를 반환합니다. 이 코드는 사용자 정보에 접근하기 위한 임시 코드로, 토큰을 받아오는 단계에서 사용됩니다.
  4. Access Token Request
    어플리케이션은 받은 인증 코드를 이용하여 인증 서버에 액세스 토큰을 요청합니다.
  5. Access Token Response
    인증 서버는 인증 코드를 검증한 후, 유효하면 액세스 토큰을 발급합니다.
  6. Access User Info
    어플리케이션은 액세스 토큰을 사용하여 사용자 정보를 요청하고, OAuth2 제공자는 이 토큰을 검증한 후, 요청된 사용자 정보를 제공합니다.

문제 발생 코드

@GetMapping("")
        @ApiOperation(value = "채팅방 리스트 조회 ", notes = "전체 채팅방 목록을 조회한다")
        public String chatRoomList(Model model, @AuthenticationPrincipal SessionUser sessionUser) {
            model.addAttribute("list",chatRoomService.findAllRooms());
            log.info("채팅방 설정 =" + chatRoomService.findAllRooms());
            // 세션에 저장된 로그인 정보를 모델에 추가
            if (sessionUser != null) {
                model.addAttribute("user", sessionUser.getAttributes());
            }
            log.info("유저 정보 =" + sessionUser.getAttributes());
            return "roomlist";
        }

문제 원인 분석

  • Spring Security의 OAuth2 로그인을 사용하여 사용자 인증을 처리하는 중, 인증된 사용자 정보(SessionUser)가 SecurityContext에 제대로 저장되지 않았다.
  • 따라서, @AuthenticationPrincipal SessionUser sessionUser 어노테이션을 사용한 컨트롤러에서 sessionUser 객체가 null로 주입되었다.

해결 방법
-> 사용자 인증을 처리하는 곳을 다시 한번 살펴보자

문제 원인 코드

@Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
        OAuth2User oAuth2User = delegate.loadUser(userRequest);
        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();



        OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
        ChatUser chatUser = saveOrUpdate(attributes);

        log.info("custon 부분 유저: "+chatUser);
        log.info("custon 부분 유저2: "+httpSession.getId());

        return new SessionUser(chatUser);

    }
  • loadUser 메서드: OAuth2UserRequest를 받아서 OAuth2User를 반환하는 메서드입니다. 이 메서드는 OAuth2 로그인 요청을 처리하고, 사용자 정보를 가져와서 처리
  • 코드를 살펴보면 OAuth2 로그인이 성공한 후, 생성된 SessionUser 객체를 SecurityContext에 저장하는 부분이 누락됨.

문제 해결

@Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
        OAuth2User oAuth2User = delegate.loadUser(userRequest);
        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();



        OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
        ChatUser chatUser = saveOrUpdate(attributes);

        log.info("custon 부분 유저: "+chatUser);
        log.info("custon 부분 유저2: "+httpSession.getId());

        SessionUser sessionUser = new SessionUser(chatUser);

        Authentication authentication = new UsernamePasswordAuthenticationToken(sessionUser, null, sessionUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        return sessionUser;

    }

🔎정리


소셜 로그인에는 성공했는데, 다른 연동된 서비스를 구현할 때 문제가 생기면 먼저 인증/인가 처리하는 곳을 문제가 있는지 살펴보자!

profile
백엔드 공부중입니다!

0개의 댓글