이전 구글 로그인에 이어서 페이스북 로그인도 진행해보려 한다.
https://growth-coder.tistory.com/136
페이스북 개발자 센터로 들어가서 로그인 하고 우측 상단의 Get Started로 들어간다.
https://developers.facebook.com/
인증 과정의 순서대로 진행한다.
모두 진행하고 나면 앱을 생성할 수 있다. 앱 만들기를 눌러서 앱을 생성한다.
앱 유형을 소비자로 선택한다.
앱 이름을 정하고 생성한다.
앱이 생성되고 나면 제품을 추가해야한다.
페이스북 로그인을 할 것이기 때문에 페이스북 로그인을 설정한다.
웹 페이지에 사용해야하므로 웹을 선택한다.
로컬 환경에서 스프링 부트를 띄워 진행할 예정이므로 스프링 부트의 기본 url을 입력해준다.
이후 여러 단계들이 있는데 일단 모두 스킵한다.
이제 좌측 메뉴의 기본 설정으로 들어간다.
앱 ID와 시크릿 코드를 확인할 수 있는데 이를 application.properties에 입력해줘야한다.
이전 구글 로그인과 형식은 똑같다.
<application.properties>
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/[데이터베이스 이름]
spring.datasource.username=root
spring.datasource.password=[비밀번호]
spring.profiles.include=oauth
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.security.oauth2.client.registration.google.client-id=[클라이언트 아이디]
spring.security.oauth2.client.registration.google.client-secret=[클라이언트 시크릿]
spring.security.oauth2.client.registration.google.scope=profile, email
spring.security.oauth2.client.registration.facebook.client-id=[앱 아이디]
spring.security.oauth2.client.registration.facebook.client-secret=[앱 시크릿 코드]
spring.security.oauth2.client.registration.facebook.scope=public_profile, email
이제 페이스북 로그인을 진행할 버튼을 resource/templates 폴더 하위에 loginForm.html에 추가해준다.
url은 "/oauth2/authorization/facebook"이다.
<loginForm.html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>로그인</title>
</head>
<body>
<form action="/login" method="post">
<input type="text" name="name"> <br>
<input type="password" name="password">
<button>제출</button>
</form>
<a href="/oauth2/authorization/google">google login</a>
<a href="/oauth2/authorization/facebook">facebook login</a>
<a href="/joinForm">회원가입 하러 가기 </a>
</body>
</html>
이전 포스팅에서 DefaultOAuth2UserService를 확장한 클래스의 loadUser 함수가 provider 로부터 받아온 userRequest를 처리해준다고 배웠다.
구글과 페이스북의 userRequest와 OAuth2User의 attributes의 형태는 거의 동일하나 약간의 차이가 존재한다.
google의 attributes 형태는 다음과 같다.
{
sub=111111111111,
name=홍길동,
given_name=길동,
family_name홍,
picture=[이미지 url]
email=email@gmail.com,
email_verified=true,
locale=ko
}
facebook의 attributes 형태는 다음과 같다.
{
id=107956215586143,
name=김철수,
email=adgildong1@gmail.com
}
같은 의미를 가지는 값의 key 값이 서로 다르기 때문에 이전에 작성한 구글 로그인을 그대로 사용하면 문제가 발생할 수 있다.
구글과 페이스북을 따로 처리하기 위해서 인터페이스를 생성한다.
public interface OAuth2MemberInfo {
String getProviderId(); //공급자 아이디 ex) google, facebook
String getProvider(); //공급자 ex) google, facebook
String getName(); //사용자 이름 ex) 홍길동
String getEmail(); //사용자 이메일 ex) gildong@gmail.com
}
이제 구글과 페이스북에 대해서 이 인터페이스를 각각 구현하기만 하면 된다.
그리고 각각의 구현체는 attributes를 가지고 있어야 한다.
이제 각각의 구현체를 생성할 차례이다.
<GoogleMemberInfo>
public class FacebookMemberInfo implements OAuth2MemberInfo{
private Map<String, Object> attributes;
@Override
public String getProviderId() {
return (String) attributes.get("id");
}
@Override
public String getProvider() {
return "facebook";
}
@Override
public String getName() {
return (String) attributes.get("name");
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
}
<FacebookMemberInfo>
public class FacebookMemberInfo implements OAuth2MemberInfo{
private Map<String, Object> attributes;
@Override
public String getProviderId() {
return (String) attributes.get("id");
}
@Override
public String getProvider() {
return "facebook";
}
@Override
public String getName() {
return (String) attributes.get("name");
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
}
이제 provider에 따라 구현체를 달리 사용하면 된다.
loadUser 메소드를 다음과 같이 고치면 된다.
@Service
@RequiredArgsConstructor
public class OAuth2MemberService extends DefaultOAuth2UserService {
private final BCryptPasswordEncoder encoder;
private final MemberRepository memberRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
OAuth2MemberInfo memberInfo = null;
System.out.println(userRequest.getClientRegistration().getRegistrationId());
if (userRequest.getClientRegistration().getRegistrationId().equals("google")) {
memberInfo = new GoogleMemberInfo(oAuth2User.getAttributes());
} else if (userRequest.getClientRegistration().getRegistrationId().equals("facebook")) {
memberInfo = new FacebookMemberInfo(oAuth2User.getAttributes());
} else {
System.out.println("로그인 실패");
}
String provider = memberInfo.getProvider();
String providerId = memberInfo.getProviderId();
String username = provider + "_" + providerId; //중복이 발생하지 않도록 provider와 providerId를 조합
String email = memberInfo.getEmail();
String role = "ROLE_ADMIN"; //일반 유저
System.out.println(oAuth2User.getAttributes());
Optional<Member> findMember = memberRepository.findByName(username);
Member member=null;
if (findMember.isEmpty()) { //찾지 못했다면
member = Member.builder()
.name(username)
.email(email)
.password(encoder.encode("password"))
.role(role)
.provider(provider)
.providerId(providerId).build();
memberRepository.save(member);
}
else{
member=findMember.get();
}
return new PrincipalDetails(member, oAuth2User.getAttributes());
}
}
참고
'공부 > Spring' 카테고리의 다른 글
[Spring][WebSocket] 스프링 STOMP와 웹 소켓 개념 및 사용법 (Web Socket with STOMP) (1) (2) | 2023.04.20 |
---|---|
[Spring] 스프링 OAuth2 네이버 로그인 (OAuth2 스프링 4편) (0) | 2023.04.01 |
[Spring] 스프링 Oauth2 구글 로그인과 jpa 사용하여 유저 정보 데이터베이스에 저장 및 권한 설정 (OAuth2 스프링 2편) (1) | 2023.03.24 |
[Spring] 스프링 Oauth2 구글 로그인과 jpa 사용하여 유저 정보 데이터베이스에 저장 (OAuth2 스프링 1편) (0) | 2023.03.23 |
[Spring][인프런 스프링 MVC] 파일 업로드 및 저장 방법 (0) | 2023.03.20 |
댓글