provider는 OAuth 제공자이고, providerId는 OAuth 제공자가 주는 id이다.
회원가입 시에 엔티티 id 값은 중요하지 않기 때문에 제외한다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
public User(){}
@Builder
public User(String username, String password, String email, String role, String provider, String providerId, Timestamp createDate) {
this.username = username;
this.password = password;
this.email = email;
this.role = role;
this.provider = provider;
this.providerId = providerId;
this.createDate = createDate;
}
}
DefaultOAuth2UserService를 상속한 서비스 클래스의 loadUser()메서드에 회원 가입 로직을 추가한다.
(단, 이 서비스 클래스는 OAuth2 관련 작업만 처리한다. 사용자 정의 관련 작업은 다른 곳에서 마저 해야 한다.)
loadUser()메서드는 userRequest 데이터에 대해 후처리를 담당해준다.
만약 로딩된 OAuth2User의 username이 서버 리포지토리 내에 없을 경우 save()를 이용해 회원가입을 진행하게 하였다.
이 메서드는 OAuth2User를 리턴하는데, 시큐리티 세션 내의 Authentication 객체가 이 리턴 값을 포함하게 된다.
따라서 이 메서드 실행이 종료되고 나면@AuthenticationPrincipal 어노테이션의 효력이 생긴다.
@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private UserRepository userRepository;
//구글로부터 받은 userRequest 데이터에 대한 후처리를 담당하는 메서드
//이 메서드 실행이 종료되고 나서 @AuthenticationPrincipal 어노테이션이 생성된다.
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User=super.loadUser(userRequest);
String provider=userRequest.getClientRegistration().getClientId();// google
String providerId= (String) oAuth2User.getAttributes().get("sub");
String username=provider+"_"+providerId;//username 은 유니크해야하므로 이와 같이 만듬.
String password=bCryptPasswordEncoder.encode("겟인데어");//Oauth 로그인일 경우, password는 딱히 의미가 없음.
String email= (String) oAuth2User.getAttributes().get("email");
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());
}
}
PrincipalDetails는 UserDetails와 OAuth2User를 모두 implements한 구현체이다.
따라서 @AuthenticationPrincipal 의 효력이 생기고 나면, 해당 구현체는 OAuth 세션 정보도 담을 수 있고 사용자 정의 세션 정보도 담을 수 있게 된다.
//Oauth 로그인을 하던, 일반 로그인을 하던 PrincipalDetails 로 받을 수 있게 되었다.
@GetMapping("/user")
public @ResponseBody
String user(@AuthenticationPrincipal PrincipalDetails principalDetails) {
System.out.println("principal Details : "+principalDetails.getUser());
return "user";
}