이번에는 Facebook을 사용하여 로그인을 해보자.
Facebook API 키와 비밀번호 얻는 것은 검색해서 알아보고, 코드에 집중하자.
먼저 설정을 해줘야 한다.
application
파일을 다음 코드를 추가해준다.
facebook:
client-id: 2896863515994895
client-secret: 0b1188709aae1c788b312221a2fd5f6c
scope:
- email
- public_profile
지난번에 구글 로그인을 하기 위해 이것저것 코드를 추가하였다.
페이스북 로그인 역시 지난번에 추가한 코드를 거의 그대로 사용한다.
먼저 로그인 폼에 페이스북 로그인을 할 수 있도록 코드를 추가한다.
<a href="/oauth2/authorization/facebook">페이스북 로그인</a>
URI는 고정이다.
public class SecurityConfig {
private final PrincipalOauth2UserService principalOauth2UserService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
(생략)
.defaultSuccessUrl("/")
.and()
.oauth2Login()
.loginPage("/loginForm")
.userInfoEndpoint()
.userService(principalOauth2UserService);
return http.build();
}
SecurityConfig
클래스에서 OAuth 로그인을 할 수 있도록 설정하고, 소셜 로그인이 완료되면 후처리는 principalOauth2UserService
클래스에서 담당한다.
principalOauth2UserService
클래스에 OAuth 로그인의 후처리하는 코드가 있는데, 구글에서 제공하는 Attributes와 페이스북에서 제공하는 Attributes가 다르기 때문에 지난번 코드를 그대로 사용하면 DB에 제대로 저장이 되지 않는다.
그래서 다음에 다른 소셜로그인을 추가하여도 principalOauth2UserService
클래스의 코드를 수정하는 일이 없게 인터페이스를 생성하여 코드를 분리하도록 하자.
public interface OAuth2UserInfo {
String getProviderId();
String getProvider();
String getEmail();
String getName();
}
public class GoogleUserInfo implements OAuth2UserInfo{
private Map<String, Object> attributes;
public GoogleUserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
}
@Override
public String getProviderId() {
return (String) attributes.get("sub");
}
@Override
public String getProvider() {
return "google";
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getName() {
return (String) attributes.get("name");
}
}
public class FacebookUserInfo implements OAuth2UserInfo{
private Map<String, Object> attributes;
public FacebookUserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
}
@Override
public String getProviderId() {
return (String) attributes.get("id");
}
@Override
public String getProvider() {
return "facebook";
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getName() {
return (String) attributes.get("name");
}
}
위의 코드들을 보면 Attributes를 받아서 회원가입에 필요한 정보들을 반환하는 메소드들로 구성되어있다.
이제 다음은 PrincipalOauth2UserService
클래스에서 코드를 수정하자.
@Service
@RequiredArgsConstructor
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
OAuth2UserInfo oAuth2UserInfo = null;
if (userRequest.getClientRegistration().getRegistrationId().equals("google")) {
System.out.println("구글 로그인 요청");
oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
} else if (userRequest.getClientRegistration().getRegistrationId().equals("facebook")) {
System.out.println("페이스북 로그인 요청");
oAuth2UserInfo = new FacebookUserInfo(oAuth2User.getAttributes());
} else {
System.out.println("우리는 구글과 페이스북만 지원한다.");
}
String provider = oAuth2UserInfo.getProvider();
String providerId = oAuth2UserInfo.getProviderId();
String username = provider + "_" + providerId;
String password = bCryptPasswordEncoder.encode("겟인데어");
String email = oAuth2UserInfo.getEmail();
String role = "ROLE_USER";
User userEntity = userRepository.findByUsername(username);
if (userEntity == null) {
userEntity = User.builder()
.username(username)
.password(password)
.email(email)
.role(role)
.provider(provider)
.providerId(providerId)
.build();
userRepository.save(userEntity);
}
return new PrincipalDetails(userEntity, oAuth2User.getAttributes());
}
}
userRequest.getClientRegistration().getRegistrationId()
의 값이 "google"인지 "facebook"인지에 따라 생성되는 인스턴스가 달라진다.
생성된 인스턴스를 통해 회원의 정보가 입력되고 회원가입이 진행된다.
이로써 페이스북으로 로그인을 할 수 있다.