Search
🔐

소셜로그인 중복허용과 코드변경

Person
태그
인증/인가
소셜로그인
OAuth2.0

문제의 발단

이전에는 회원가입의 경로가 하나뿐이라 이메일 중복검사를 할 때 고려할 사항이 없었는데 소셜로그인이 들어오면서 각 소셜로그인과 일반 로그인에서 이메일이 중복 될 수 있게 되었습니다.
예를 들어 저의 카카오 아이디가 wldsmtldsm65@gmail.com 이고 구글 이메일 또한 이와 같다면 가입할 때 이전 로직과 같은식으로 이메일 중복을 검사한다면 카카오 로그인 혹은 구글 이메일 중 하나만 선택 해야 합니다. 만약 일반 회원가입을 저 이메일로 했다면 소셜 로그인은 하지 못하겠죠.
이는 유저경험에 아주 좋지 않을 뿐더러 일반적인 홈페이지를 생각할 때 말이 안되기도 합니다. 때문에 각 소셜 로그인마다 중복 이메일을 한개씩 둘 수 있도록 하였습니다. 이에 따라 약간의 변경 사항들이 생겼고, 그로 인한 문제 상황과 해결 방법을 적어보았습니다.

웹토큰 생성 방식의 변경

이전에는 웹토큰 생성 시 claims 에 이메일을 넣어 헤더로 받은 토큰을 까서 나오는 이메일로 유저 인증 절차를 밟았습니다. 하지만 이제는 이메일이 중복 될 수 있기 때문에 이메일이 아닌, userId 를 claims 에 넣었습니다.
때문에 이제 웹토큰을 까보면 이메일이 아닌 String 형태의 userId 가 나올 것입니다. 웹토큰의 경우 Long 타입을 사용할 수 없고 String 타입만 사용할 수 있으므로 이 점 유의해주세요.
public String generateAccessToken(String userId) { Claims claims = Jwts.claims().setSubject(userId); Date now = new Date(); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(new Date(now.getTime() + AccessTokenValidTime)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }
Java
복사

getCurrentMember() 메서드 변경

현재 로그인한 유저를 찾기 위해 AuthUtil 에 getCurrentMember() 메서드를 만들어두었습니다. 처음에 만든 코드는 아래와 같습니다.
public Member getCurrentMember() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String username = authentication.getName(); return memberRepository.findByEmail(username) }
Java
복사
웹토큰 인증을 거쳐서 시큐리티 컨텍스트 홀더에 저장된 유저의 이메일을 꺼내오고, 이를 통해 멤버를 찾는 로직이였습니다. 하지만 바뀐 로직의 경우 위와 같이하면 단일 맴버 객체가 아니고 여러 멤버가 나오는 현상이 발생할 수 있습니다. 따라서 코드를 아래와 같이 변경하였습니다.
public Member getCurrentMember(HttpServletRequest request) { String accessToken = tokenUtil.getJWTTokenFromHeader(request); String userId = tokenUtil.getUserIdFromToken(accessToken); return memberRepository.findById(Long.valueOf(userId)) .orElseThrow(() -> new ApiException(ErrorType.USER_NOT_FOUND)); }
Java
복사
이를 통해 로그인 시 발급받은 웹토큰을 통해 현재 로그인한 유저의 정보를 가져올 수 있습니다. 하지만 웹소켓의 경우 HttpServletRequest 를 이용할 수 없습니다. 둘은 다른 프로토콜이기 때문입니다. 따라서 웹소켓의 경우 아래와 같이 따로 작성해주었습니다.
public Member getCurrentMemberForWebSocket(String accessToken) { String userId = tokenUtil.getUserIdFromToken(accessToken); return memberRepository.findById(Long.valueOf(userId)) .orElseThrow(() -> new ApiException(ErrorType.USER_NOT_FOUND)); }
Java
복사
이 메서드의 경우 글을 작성한 사람과 로그인한 사람이 일치하는가? 등을 판단하기 위한 메서드 이기 때문에 위와 같이 구현해도 충분하다 생각했습니다. 혹여 다른 의견이 있다면 알려주세요!

 ChatGPT 가 말하는 HttpServeletRequest 와 웹소켓