dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.mysql:mysql-connector-j'
}
${ } 사용하여 환경변수로 지정!
spring:
security:
oauth2:
client:
registration:
naver:
client-name: naver
client-id: ${NAVER_CLIENT_ID}
client-secret: ${NAVER_CLIENT_SECRET}
redirect-uri: ${NAVER_REDIRECT_URI}
authorization-grant-type: authorization_code
scope:
- name
- email
kakao:
client-id: ${KAKAO_CLIENT_ID}
client-secret: ${KAKAO_CLIENT_SECRET}
scope:
- profile_nickname
- account_email
client-name: Kakao
authorization-grant-type: authorization_code
redirect-uri: ${KAKAO_REDIRECT_URI}
client-authentication-method: client_secret_post
provider:
naver:
authorization-uri: https://nid.naver.com/oauth2.0/authorize
token-uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
user-name-attribute: response
kakao:
authorization-uri: https://kauth.kakao.com/oauth/authorize
token-uri: https://kauth.kakao.com/oauth/token
user-info-uri: https://kapi.kakao.com/v2/user/me
user-name-attribute: id
@Data
public class PrincipalDetails implements UserDetails, OAuth2User {
private User user;
private Map<String,Object> attributes;
public PrincipalDetails(User user) {
this.user = user;
}
//Oauth 로그인을 할때 사용하는 생성자
public PrincipalDetails(User user, Map<String, Object> attributes) {
this.user = user;
this.attributes = attributes;
}
@Override
public String getName() {return user.getName();}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add((GrantedAuthority) () -> user.getRole().getAuthority());
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
getAuthorities()
: 사용자 권한(Role) 반환
getAttributes()
: OAuth2 로그인 시 제공되는 사용자 정보 처리
@Service
@Slf4j
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
@Autowired
private UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
log.info("getClientRegistration : " + userRequest.getClientRegistration());
log.info("getAccessToken : " + userRequest.getAccessToken().getTokenValue());
OAuth2User oAuth2User = super.loadUser(userRequest);
log.info("getAttributes : " + oAuth2User.getAttributes());
OAuth2Response oAuth2UserInfo = null;
if (userRequest.getClientRegistration().getRegistrationId().equals("kakao")) {
System.out.println("카카오 로그인 요청");
oAuth2UserInfo = new KakaoUserInfo(oAuth2User.getAttributes());
} else if (userRequest.getClientRegistration().getRegistrationId().equals("naver")) {
System.out.println("네이버 로그인 요청");
oAuth2UserInfo = new NaverUserInfo((Map<String, Object>) oAuth2User.getAttributes().get("response"));
} else {
throw new OAuth2AuthenticationException("Unsupported provider");
}
String provider = oAuth2UserInfo.getProvider();
String providerId = oAuth2UserInfo.getProviderId();
String name = oAuth2UserInfo.getName();
String email = oAuth2UserInfo.getEmail();
Role role = Role.USER;
User userEntity = userRepository.findByEmail(email);
if(userEntity == null) {
System.out.println("Oauth인이 최초입니다.");
userEntity = User.builder()
.name(name)
.email(email)
.nickname(name)
.role(role)
.provider(provider)
.providerId(providerId)
.build();
userRepository.save(userEntity);
} else {
System.out.println("로그인을 이미 한 적이 있습니다.");
}
return new PrincipalDetails(userEntity, oAuth2User.getAttributes());
}
}
loadUser() 메서드
public interface OAuth2Response {
String getProvider();
String getProviderId();
String getEmail();
String getName();
}
public class NaverUserInfo implements OAuth2Response {
private Map<String, Object> attributes; //getAttributes()
public NaverUserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
}
@Override
public String getProviderId() {
return (String)attributes.get("id");
}
@Override
public String getProvider() {
return "naver";
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getName() {
return (String) attributes.get("name");
}
}
public class KakaoUserInfo implements OAuth2Response{
private Map<String, Object> attributes; //getAttributes()
public KakaoUserInfo(Map<String, Object> attributes) {
if (attributes == null) {
throw new IllegalArgumentException("Attributes map cannot be null");
}
this.attributes = attributes;
}
@Override
public String getProvider() {
return "kakao";
}
@Override
public String getProviderId() {
return String.valueOf(attributes.get("id"));
}
@Override
public String getEmail() {
Map<String, Object> kakaoAccount = (Map<String, Object>) attributes.get("kakao_account");
return String.valueOf(kakaoAccount.get("email"));
}
@Override
public String getName() {
Map<String, Object> properties = (Map<String, Object>) attributes.get("properties");
if (properties != null) {
return String.valueOf(properties.get("nickname"));
}
return null;
}
}