2 분 소요

Spring Security, OAuth2.0으로 구글 로그인“을 보지 않으신 분은 먼저 보시고 오시면 좋습니다!

Github Oauth2.0

Client ID 발급

Github_step1

Github에서 오른쪽 위에 사용자를 누른 뒤 Setting을 눌러줍니다.



Github_step2

Developer settings를 눌러주세요.



Github_step3

OAuth Apps를 눌러주신 후 OAuth App을 만들어 주세요.



Github_step4

Application name: 앱 이름
Hmepage URL: http://localhost:8080
Authorization callback URL: http://localhost:8080/login/oauth2/code/github

실제 테스트이기 때문에 localhost로 해주었습니다. 추후에 변경하시면 됩니다.



application 설정

spring:
  security:
    oauth2:
      client:
        registration:
            github:
                client-id: Client ID
                client-secret: Client secrets

생성된 앱에서 Client IDClient secrets를 입력해줍니다.



code 수정

Member

@Entity
@Getter @Setter
@NoArgsConstructor
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id; //기본키
    private String name; //유저 이름
    private String memberProviderId; // 공급자_공급 아이디
    private String provider; //공급자 (google, github ...)
    private String providerId; //공급 아이디

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private Role role; //유저 권한 (관리자, 고객)

    @Builder
    public Member(String name, String memberProviderId, Role role, String provider, String providerId) {
        this.name = name;
        this.memberProviderId = memberProviderId;
        this.role = role;
        this.provider = provider;
        this.providerId = providerId;
    }
}

기존 Member는 Email이 있었는데 Github는 Email값을 사용자가 따로 설정하지 않는다면 null값을 반환하기 때문에 Resource Server에서 공통적으로 제공하는 provider, providerId값을 이용해서 사용자 검색용 column을 생성해줍니다.



MemberRepository

public interface MemberRepository extends JpaRepository<Member, Long> {

    public Member getOne(Long id);
    public List<Member> findByMemberProviderId(String MemberProviderId);
}

기존 Email로 찾는 방식말고 MemberProviderId로 찾는 메서드를 생성해줍니다.



OAuthAttributes

public class OAuthAttributes {
    private Map<String, Object> attributes;
    private String name;
    private String providerAndId;
    private String provider;
    private String providerId;
    private Role role;

    @Builder
    public OAuthAttributes(Map<String, Object> attributes, String name, String providerAndId, String provider, String providerId, Role role) {
        this.attributes = attributes;
        this.name = name;
        this.providerAndId = providerAndId;
        this.provider = provider;
        this.providerId = providerId;
        this.role = role;
    }

    // Google, Github 로그인 구별
    public  static OAuthAttributes of(String provider, Map<String, Object> attributes, Role role) throws Exception {
        switch (provider) {
            case "google":
                return ofGoogle(provider, attributes, role);
            case "github":
                return ofGithub(provider, attributes, role);
            default:
                throw new Exception("지원하지 않는 로그인입니다.");
        }


    }

    // Google 로그인 처리
    private static OAuthAttributes ofGoogle(String provider, Map<String, Object> attributes, Role role) {
        return OAuthAttributes.builder()
                .attributes(attributes)
                .name((String) attributes.get("name"))
                .providerAndId(provider + "_" + attributes.get("sub"))
                .provider(provider)
                .providerId((String) attributes.get("sub"))
                .role(role)
                .build();
    }
    
    // Github 로그인 처리
    private static OAuthAttributes ofGithub(String registrationId, Map<String, Object> attributes, Role role) {
        return OAuthAttributes.builder()
                .attributes(attributes)
                .name((String) attributes.get("name"))
                .providerAndId(registrationId + "_" + attributes.get("id"))
                .provider(registrationId)
                .providerId(String.valueOf(attributes.get("id")))
                .role(role)
                .build();
    }

    public Member toEntity() {
        return Member.builder()
                .name(name)
                .memberProviderId(providerAndId)
                .role(Role.USER)
                .provider(provider)
                .providerId(providerId)
                .build();
    }
}

DTO로 OAuthAttributes를 생성해줍니다. OAuthAttributes는 다양한 소셜 로그인을 해도 같은 Member Class를 생성해주는 DTO입니다.



OAuth2MemberService

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OAuth2MemberService extends DefaultOAuth2UserService {
    private final MemberRepository memberRepository;
    @Override
    @Transactional
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);

        // name 생성
        String provider = userRequest.getClientRegistration().getRegistrationId(); //google
        String providerId = oAuth2User.getAttribute("sub");
        String findByMemberProviderId = provider + "_" + providerId;
        Map<String, Object> attributes = oAuth2User.getAttributes();
        Role role = Role.USER; //일반 유저

        List<Member> members = memberRepository.findByMemberProviderId(findByMemberProviderId);
        Member member;
        if (members.isEmpty()) { //최초 로그인
            try {
                member = OAuthAttributes.of(provider, attributes, role).toEntity();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            memberRepository.save(member);
        } else{ // 기존 고객
            member = members.get(0);
        }

        return new PrincipalDetails(member,  oAuth2User.getAttributes());
    }
}

OAuthAttributes를 통해 Member 객체를 생성함으로 OAuth2MemberServiceOAuthAttributes.of()를 이용해서 Member 객채를 저장할 수 있도록 해줍니다.



Home.html

<a sec:authentication="principal.member.name"/>
(<a sec:authentication="principal.member.email"/>)님 안녕하세요!

to

<a sec:authentication="principal.member.name"/>님 안녕하세요!

member의 email이 없으므로 home.html도 위와 같이 수정해주시면 됩니다.



loginForm.html

<a class="button button--social-login button--github" href="/oauth2/authorization/github">Login With Github</a>

Google 로그인 버튼 아래에 Github 로그인 버튼을 추가해줍니다.
주소를 /oauth2/authorization/github로 해주시면 됩니다.



결과

result

구글, GitHub로 로그인해보면 다음과 같이 DB에 저장된 것을 확인할 수 있습니다.



Github

https://github.com/HYLogs/OAuth2.0/tree/GoogleAndGithubOAuth

댓글남기기