본문 바로가기
프로젝트/낙낙(KnockKnock)

OAuth2 again!!!

by 티코딩 2023. 10. 30.

내가 여태껏 구현한 oauth는 프론트가 웹일때의 경우였다. 프론트 분들이 페이지만 만들면 된다 생각했는데 생각해보니 모바일앱은 페이지주소가 없다. 그래서 앱 개발 경험이 있는 친구에게 물어봤더니 전체적인 시퀀스가 너무 달랐다. 웹에서는 서버에서 하는일이 많았지만 앱인 경우엔 생각보다 서버는 할게 많이 없다. 내가 원래 짰던 시퀀스는이렇다.

하지만 내가 다시 구현해야 할 시퀀스는 아래와 같다.

내가 찾아본 블로그에서는 카카오는 이렇게 구현하고,

구글은 아래와 같이 구현해야 한다고 한다.

이제 프론트 분들이 받아오는 데이터를 보자.

구글에서는 이름, 이메일, id를 받아온다. 카카오는 아직 권한이 없어서 아이디만 받아와진다. 공통적으로 id만 받아오기 때문에 내가 개발해야 할 API는 ID, ProviderType을 입력받아 해당 ID가 DB에 존재하면 로그인처리하고 토큰을 응답값에 담아보내주고, 만약 DB에 해당 ID가 없으면 회원가입 처리를 하고 토큰을 응답값에 담아 보내주는 API이다.

 

ㅇ 컨트롤러

@PostMapping("/oauth")
    public ApiResponse loginOrSignup(@Validated @RequestBody UserDto.LoginOrSignup requestBody, HttpServletRequest request, HttpServletResponse response) {
        Optional<User> userOptional = userRepository.findById(requestBody.getUserId());

        //userId로 찾았을 때 DB에 있으면, 만료됐으면 새롭게 토큰발급
        if(userOptional.isPresent()){
            Date now = new Date();
            AuthToken accessToken = tokenProvider.createAuthToken(requestBody.getUserId(), new Date(now.getTime() +
                    appProperties.getAuth().getTokenExpiry()));

            long refreshTokenExpiry = appProperties.getAuth().getRefreshTokenExpiry();
            AuthToken refreshToken = tokenProvider.createAuthToken(
                    appProperties.getAuth().getTokenSecret(),
                    new Date(now.getTime() + refreshTokenExpiry)
            );

            // userId refresh token 으로 DB 확인
            UserRefreshToken userRefreshToken = userRefreshTokenRepository.findByUserId(requestBody.getUserId());
            if (userRefreshToken == null) {
                // 없는 경우 새로 등록
                userRefreshToken = new UserRefreshToken(requestBody.getUserId(), refreshToken.getToken());
                userRefreshTokenRepository.saveAndFlush(userRefreshToken);
            } else {
                // DB에 refresh 토큰 업데이트
                userRefreshToken.setRefreshToken(refreshToken.getToken());
            }

            int cookieMaxAge = (int) refreshTokenExpiry / 60;
            CookieUtil.deleteCookie(request, response, REFRESH_TOKEN);
            CookieUtil.addCookie(response, REFRESH_TOKEN, refreshToken.getToken(), cookieMaxAge);

            return ApiResponse.success("token", accessToken.getToken());
        } else{
            //회원가입 처리
            User user = userService.oauthSignup(requestBody.getUserId(), requestBody.getProviderType());
            Date now = new Date();
            AuthToken accessToken = tokenProvider.createAuthToken(requestBody.getUserId(), new Date(now.getTime() +
                    appProperties.getAuth().getTokenExpiry()));

            long refreshTokenExpiry = appProperties.getAuth().getRefreshTokenExpiry();
            AuthToken refreshToken = tokenProvider.createAuthToken(
                    appProperties.getAuth().getTokenSecret(),
                    new Date(now.getTime() + refreshTokenExpiry)
            );
            int cookieMaxAge = (int) refreshTokenExpiry / 60;
            CookieUtil.deleteCookie(request, response, REFRESH_TOKEN);
            CookieUtil.addCookie(response, REFRESH_TOKEN, refreshToken.getToken(), cookieMaxAge);

            return ApiResponse.success("token", accessToken.getToken());
        }
	}

ㅇ 서비스

public User oauthSignup(String userId,ProviderType providerType){
        //중복 Id 체크
        verifyExistsUserId(userId);

        // 빌더 패턴을 사용하여 User 객체 생성
        User newUser = User.builder()
                .id(userId)
                .password("abcdefg!!")
                .pushAgree(false)
                .emailVerifiedYn("Y")
                .providerType(providerType)
                .roleType(RoleType.USER)
                .createdAt(LocalDateTime.now())
                .modifiedAt(LocalDateTime.now())
                .build();
        //user 저장
        return userRepository.save(newUser);
    }

패스워드는 어차피 쓰이지 않지만 null일 수 없어서 임의의값을 넣어줬다. 

 

나중에 우리 앱이 심사에 통과해서 정보를 많이 불러올 수 있으면 그때 dto를 바꾸고 서비스 파라미터만 바꿔주면 된다.

이제 다 했다. 앱 빌드만 통과하면 된다!! 끝!!!