본문 바로가기
Spring

[Spring] 로그인 구현 번외 - 소셜 로그인 시 권한 부여

by Bhinney 2022. 12. 20.

메인 프로젝트를 하면서 REST API로 카카오 로그인을 구현해보았다.

해당 부분을 기억하기 위해 이 글을 작성하였다.

이 포스팅은 프로젝트 과정에서 흐름을 기억하기 위해 작성한 것으로, 기본 흐름의 틀정도라고 생각하면 좋을 듯 하다.

해당 포스팅의 코드는 아래의 깃헙 주소에서도 확인 가능.

❗️본 포스팅은 이전 포스팅에서 이어집니다❗️

 

GitHub - Bhinney/Study: ✨ 공부하면서 기록하는 공간 ✨

✨ 공부하면서 기록하는 공간 ✨. Contribute to Bhinney/Study development by creating an account on GitHub.

github.com


✨ 들어가기 전에 왜 권한 수정이 로그인에 같이 포스팅 하는지

: 메인 프로젝트 서버는 생산자와 소비자가 나뉘어져 있었다. 그렇기 때문에 무조건 둘 중의 하나의 역할을 선택하고 해당 권한이 있어야 했다. 하지만 소셜 로그인 사용자는 선택하기 어렵기 때문에, 따로 선택할 수 있는 페이지를 만들었다. 중요한 것은 이 페이지는 "소셜"권한 사용자만 접근이 가능하다는 것이다. 만약 생산자나 소비자로 역할을 선택했다면 그 이후에는 접근이 불가하다.

왜냐하면, 한 번 정해진 역할(권한)은 수정할 수 없기 때문이다.


1️⃣ PatchDto 클래스 생성

  • 요청이 들어올 DTO 클래스를 생성
@Getter
public class SocialPatchDto {
   private String role;
}

2️⃣ MemberService에 소셜 권한 관련 함수 추가

  • MemberService 클래스에 소셜 권한을 위한 함수를 추가
@Service
@Slf4j
@Transactional
@RequiredArgsConstructor
public class MemberService {
   private final MemberRepository memberRepository;
   private final PasswordEncoder passwordEncoder;
   private final CustomAuthorityUtils authorityUtils;
   private final AuthenticationManagerBuilder authenticationManagerBuilder;
   private final JwtProvider jwtProvider;
   private final RedisTemplate<String, Object> redisTemplate;
   
   ...

   /* 소셜 로그인 권한 수정 */
   public Member updateSocial(String role, long memberId) {
      Member member = findVerifiedMember(memberId);
      checkSocialRole(member.getRole());

      if (role.equalsIgnoreCase("CLIENT")) {
         member.setCreateMember(
            "소셜 로그인 사용자, 권한 수정 완료",
            "CLIENT",
            List.of("CLIENT"),
            ProviderType.KAKAO
         );
         member.setClient(new Client());
      } else if (role.equalsIgnoreCase("SELLER")) {
         member.setCreateMember(
            "소셜 로그인 사용자, 권한 수정 완료",
            "SELLER",
            List.of("SELLER"),
            ProviderType.KAKAO
         );
         member.setSeller(new Seller());
      } else {
         throw new RuntimeException("수정할 수 없습니다.");
      }

      return member;
   }
   
   ...
   
   /* 존재하는 회원인지 확인 */
   private Member findVerifiedMember(long memberId) {
   	Optional<Member> optionalMember = memberRepository.findById(memberId);
    	Member findMember = optionalMember.orElseThrow(
        	() -> new RuntimeException("회원을 찾을 수 없습니다."));
        return findMember;
   }

   /* social 역할 확인 */
   private void checkSocialRole(String role) {
      if (!role.equalsIgnoreCase("SOCIAL")) {
         throw new RuntimeException("소셜 권한 사용자가 아닙니다.");
      }
   }
}

3️⃣ MemberController에 소셜 권한 관련 함수 추가

  • MemberController 클래스에 소셜 권한을 위한 함수를 추가
  • 토큰을 재발급 받는 이유 : 토큰에는 역할이 담겨있기 때문
@Slf4j
@RestController
@RequiredArgsConstructor
@Transactional
public class MemberController {
   private final MemberService memberService;
   private final MemberMapper mapper;
   private final KakaoService kakaoService;

   /* 소셜 로그인 유저 권한 수정 */
   @PatchMapping("/social/{member_id}")
   public ResponseEntity patchSocial(@PathVariable("member_id") @Positive long memberId,
      @RequestBody SocialPatchDto requestBody) {

      Member member = memberService.updateSocial(requestBody.getRole(), memberId);
      LoginRequestDto request = new LoginRequestDto(member.getEmail(), member.getPassword());

      /* 여기서 토큰 재발급 */
      TokenDto tokenDto = memberService.kakaoLogin(request);
      HttpHeaders httpHeaders = setHeader(tokenDto.getAccessToken());

      /* 역할에 따라 응답 바디가 다르므로, 나누어 주었다.*/
      if(member.getRole().equals("SELLER")) {
         return new ResponseEntity<>(mapper.memberToSellerResponseDto(member), httpHeaders, HttpStatus.OK);
      } else if (member.getRole().equals("CLIENT")) {
         return new ResponseEntity<>(mapper.memberToClientResponseDto(member), httpHeaders, HttpStatus.OK);
      }
      /* 로그인이 실패할 경우, 문제가 존재하는 것 */
      throw new RuntimeException("로그인에 실패하였습니다.");
   }

   /* 로그인 헤더 설정 */
   private HttpHeaders setHeader(String token) {
      HttpHeaders httpHeaders = new HttpHeaders();
      httpHeaders.set("Authorization", token);

      return httpHeaders;
   }
}

 

 

댓글