웹개발/Spring Security

Spring Security 8-Kakao Login

RBWSN 2021. 10. 3. 14:24
728x90

 

今度にはKAKAOのloginを具現します。

 

まず、KAKAO developer siteに接続します。

https://developers.kakao.com/

そして、APPLICATIONを追加します。

 

 

このように、設定します。

 

そして、APPLICATION propertyを修正します。

 

spring.security.oauth2.client.registration.kakao.client-id=
spring.security.oauth2.client.registration.kakao.client-secret=
spring.security.oauth2.client.registration.kakao.scope=profile_nickname,account_email
spring.security.oauth2.client.registration.kakao.client-name=kakao
spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.kakao.client-authentication-method=post
spring.security.oauth2.client.registration.kakao.redirect-uri=http://localhost:8881/login/oauth2/code/kakao
spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
spring.security.oauth2.client.provider.kakao.user-name-attribute=id

 

kakaoのdocumentは

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api

にあります。

 

そして、

 

 

package com.rbwsn.entity;

import com.rbwsn.constant.Role;
import com.rbwsn.dto.UserFormDto;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.persistence.*;
import java.sql.Timestamp;

@Entity
@Getter @Setter
@ToString
@NoArgsConstructor
public class User {

    @Id // 基本のKEY
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String username;

    private String password;

    private String email;

    @Enumerated(EnumType.STRING)
    private Role role; // USER, ADMIN, MEMBER

    private String provider;
    private String provider_id;


    @CreationTimestamp
    private Timestamp createDate;




    public static User createUser(UserFormDto userFormDto, PasswordEncoder passwordEncoder){
        User user =new User();
        user.setProvider("local");
        user.setProvider_id("1234");
        user.setUsername(userFormDto.getUsername()+user.getProvider_id()+user.getProvider());
        user.setEmail(userFormDto.getEmail());
        String password = passwordEncoder.encode(userFormDto.getPassword());
        user.setPassword(password);
        user.setRole(Role.ROLE_ADMIN);
        return user;
    }

    @Builder
    public User(String username, String password, String email, Role role, String provider, String provider_id, Timestamp createDate) {
        this.username = username;
        this.password = password;
        this.email = email;
        this.role = role;
        this.provider = provider;
        this.provider_id = provider_id;
        this.createDate = createDate;
    }
}

 

そして、基本的でLOGINするときproviderを参照するようにSecurityDetailsServiceを修正します。

 

package com.rbwsn.auth;

import com.rbwsn.entity.User;
import com.rbwsn.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class SecurityDetailsService implements UserDetailsService{

    @Autowired
    private UserRepository userRepository;


    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmailAndProvider(email,"local");
        if(user!=null){
            return new SecurityDetails(user);
        }
        return null;

    }



}
packagecom.rbwsn.repository;

importcom.rbwsn.entity.User;
importorg.springframework.data.jpa.repository.JpaRepository;

public interfaceUserRepositoryextendsJpaRepository<User,Long> {
    User findByEmail(String email);
    User findByEmailAndProvider(String email,String provider);
    User findByUsername(String user);//重複メールチェック
}

 

これから、

KAKAOで入力になるときの設定します。

 

package com.rbwsn.oauth;

import com.rbwsn.auth.SecurityDetails;
import com.rbwsn.constant.Role;

import com.rbwsn.entity.User;
import com.rbwsn.oauth.provider.*;
import com.rbwsn.repository.UserRepository;

import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;


@Service
@Transactional
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;



    @SneakyThrows
    @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("Google Login");
            oAuth2UserInfo = new GoogleOAuth2UserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("facebook")) {
            System.out.println("Facebook Login");
            oAuth2UserInfo = new FacebookOAuth2UserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("naver")) {
            System.out.println("Naver Login");
            oAuth2UserInfo = new NaverOAuth2UserProvider(oAuth2User.getAttribute("response"));
        } else if(userRequest.getClientRegistration().getRegistrationId().equals("kakao")){
            System.out.println("Kakao Login");
            Map<String,Object> nickname = oAuth2User.getAttribute("properties");


            oAuth2UserInfo = new KakaoOAuth2UserInfo(oAuth2User.getAttribute("kakao_account")
                    ,oAuth2User.getAttribute("id").toString(),
                    nickname);
        }
        else {
            System.out.println("null");
        }
        System.out.println(oAuth2UserInfo.getProviderId());
        System.out.println(oAuth2UserInfo.getProvider());


        String provider = oAuth2UserInfo.getProvider();
        String providerId = oAuth2UserInfo.getProviderId();
        String email = oAuth2UserInfo.getEmail();
        String name = oAuth2UserInfo.getName();
        String password = passwordEncoder.encode("oauth1234");


        User user = userRepository.findByEmailAndProvider(email,provider);


        if (user == null) {
            user = User.builder()
                    .username(name+providerId+provider)
                    .provider(provider)
                    .password(password)
                    .email(email)
                    .role(Role.ROLE_USER)
                    .provider_id(providerId)
                    .build();
            userRepository.save(user);
        }


        return new SecurityDetails(user, oAuth2User.getAttributes());
    }
}

 

USERNAMEは区分するようにdbに入力になるVALUEを変えます。

kakaoのoauth2のgetAttributeが間違いますから設定します。

 

そして、KAKAOの情報を具現する KakaoOAuth2UserInfoを作ります。

package com.rbwsn.oauth.provider;

import java.util.Map;

public class KakaoOAuth2UserInfo implements OAuth2UserInfo {
    private Map<String, Object> attibutes;
    private String providerId;
    private Map<String, Object> nickName;

    public KakaoOAuth2UserInfo(Map<String, Object> attibutes, String providerId, Map<String, Object> nickName) {
        this.attibutes = attibutes;
        this.providerId = providerId;
        this.nickName = nickName;
    }

    @Override
    public String getProviderId() {
        return providerId;
    }

    @Override
    public String getProvider() {
        return "kakao";
    }

    @Override
    public String getEmail() {
        return (String) attibutes.get("email");
    }

    @Override
    public String getName() {
        return (String) nickName.get("nickname");
    }
}

 

最後にはjpaを修正します。

package com.rbwsn.repository;

import com.rbwsn.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User,Long> {
    User findByEmail(String email);
    User findByEmailAndProvider(String email,String provider);
    User findByUsername(String user);// 重複メールチェック
}

 

728x90