Coding History/Team YesY

git hub 소셜 로그인 구현

BlackBirdIT 2024. 12. 28. 10:41

원래는 리액트랑 통신이 제대로 되는가 확인을 먼저 해보려고 했는데 그냥 팀원이 할게 없대서 구조 설명해주고 버튼 하나만 만들어놓으라고 부탁했음.

그럼 나는 그냥 백엔드 로직만 만들면 되는거, 깃 허브 소셜 로그인은 어떻게 구현하는지는 깃 허브 페이지 들어가서 확인해봐야지.

여기 세팅으로 들어가서,

좌측 맨 아래에 보면 Developer settings라고 있다.

들어가서 OAuth Apps로 오면 생성하는거 있음.

여기서 이렇게 프론트를 기준으로 설정해줬음.

그럼 여기 클라이언트 아이디랑 비번 생성 가능함.

생성하면 다신 볼 수 없으니 저장하라고 알려준다.

여튼 이제 클라이언트 ID와 Secret을 알아냈으니 일단은 Yml 파일에서 설정해주자고, secret.yml을 만들었으니까 여기서 구글로그인 아래에 작성해주면 될 듯.

.env에 환경변수 저장해주고,

secret.yml에 깃허브 관련 코드를 이렇게 작성해줬음.


기본적인 설정은 마쳤으니까 이제 이걸 기존 코드에서 구글 로그인과 같은 로직으로 돌아갈 수 있게끔 만들어줘야함.

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        System.err.println("================================로그인 DB 접근로직 시작.=================================");
        // 기본적으로 OAuth2User 정보를 가져옴
        OAuth2User oAuth2User = super.loadUser(userRequest);

        // OAuth 제공자 확인 (Google 또는 GitHub)
        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String email;
        String githubLoginId;
        String googleLoginId;
        String profileImageUrl;

        if ("google".equals(registrationId)) {
            email = oAuth2User.getAttribute("email");
            googleLoginId = oAuth2User.getAttribute("sub");
            profileImageUrl = oAuth2User.getAttribute("picture");

            System.out.println("Google OAuth2로 가져온 사용자 이메일: " + email);
            System.out.println("Google OAuth2로 가져온 사용자 ID: " + googleLoginId);

            storeProfileImageInSession(profileImageUrl);
            return processGoogleUser(oAuth2User, email, googleLoginId);

        } else if ("github".equals(registrationId)) {
            email = oAuth2User.getAttribute("email");
            githubLoginId = oAuth2User.getAttribute("id").toString(); // GitHub ID는 Long이므로 String으로 변환
            profileImageUrl = oAuth2User.getAttribute("avatar_url"); // GitHub 프로필 이미지 URL

            System.out.println("GitHub OAuth2로 가져온 사용자 이메일: " + email);
            System.out.println("GitHub OAuth2로 가져온 사용자 ID: " + githubLoginId);

            storeProfileImageInSession(profileImageUrl);
            return processGitHubUser(oAuth2User, email, githubLoginId);
        } else {
            throw new OAuth2AuthenticationException("Unknown registrationId: " + registrationId);
        }
    }

기존 로직에 github 처리하는 코드를 추가했고 processGitHubUser 메서드는 따로 만들어줬음.


아 근데 여기서 processGitHubUserprocessGoogleUser메서드가 따로있는게 마음에 안드네, 통합시켜보자.

통함 시키기전에 테이블도 재정의가 필요할 것 같아서,

@Column(name = "login_id", nullable = false, unique = true, length = 255) //로그인 ID
private String loginId;

@Column(name = "provider", nullable = false, length = 20)
private String provider; // "google" 또는 "github"

기존 구글로그인아이티 칼럼을 login_id로 통합시켜주고 provider필드를 추가해서 구글인이 깃허브인지 구분하기로 했음.

    public CustomOAuth2User processOAuth2User(
            OAuth2User oAuth2User,
            String email,
            String loginId,
            String provider) {

        // DB에서 사용자 검색
        Optional<Member> localUser = memberRepository.findByEmail(email); // loginId는 Google과 GitHub 공통 ID
        boolean isNewUser;

        Member user;
        if (localUser.isPresent()) {
            // 기존 사용자
            user = localUser.get();
            isNewUser = false;
            log.info("기존 {} 사용자 확인됨: {}, isNewUser: {}", provider, email, isNewUser);
        } else {
            // 새 사용자 등록
            isNewUser = true;
            String displayName = oAuth2User.getAttribute("name") != null ? oAuth2User.getAttribute("name") : "사용자";
            String nickname = email.split("@")[0];

            user = new Member();
            user.setEmail(email);
            user.setUName(displayName);
            user.setNickname(nickname);
            user.setLoginId(loginId); // Google, GitHub 모두 loginId로 저장

            memberRepository.save(user);
            log.info("로컬 DB에 새 {} 사용자 저장 완료: {}, isNewUser: {}", provider, email, isNewUser);
        }

        // JWT 발급
        String accessToken = jwtUtil.generateToken(user.getLoginId(), user.getEmail(), user.getId(), isNewUser);
        String refreshToken = jwtUtil.generateRefreshToken(user.getLoginId(), user.getEmail(), user.getId());

        // Refresh Token Redis에 저장
        redisRefreshTokenService.saveRefreshToken(user.getEmail(), refreshToken);
        log.info("Successfully Redis Save Token for {}: {}", provider, refreshToken);

        return new CustomOAuth2User(user, oAuth2User.getAttributes(), accessToken, refreshToken, isNewUser);
    }

그리고 이렇게 하나의 메서드로 돌아가게끔 개선을 해줬음.

그리고 오류 없이 서버 돌아가는 것 까지 확인했고, 프론트에서 준비가 되면 이제 테스트 해보면서 문제가 생길시에는 수정해주면 된다.

아 그리고 새로 필드 수정하면서 DB도 체크했음.

포스트그리는 TINYINT 허용안되는거 몰랐는데 이거 때문에 DB 테이블 생성이 안되고 있었음.

@Column(name = "auth_level", nullable = false, columnDefinition = "SMALLINT DEFAULT 1") // 권한 레벨 수정
private int authLevel;

그래서 SMALLINT 사용했고, 또 숫자가 제일 앞에오면 "" 이렇게 큰 따옴표로 해야되는 규칙도 좀 거슬려서 디비버 연결 끊고,

다시 생성했음. 소문자로 시작하고 년도 월은 뒤로 가게 바꿈.

아 또,

  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect

야물 설정도 PostgreSQLDialect로 지정해줬음.

그래서 JPA도 정상 작동함.

일단 여기까지 해놓고 끊고 가야될듯.