본문 바로가기
프로젝트/Spring Boot 블로그프로젝트

[블로그프로젝트] 30. 카카오로그인(1)

by dantriss 2023. 6. 19.

유튜브에서 블로그 만들기 프로젝트를 따라하면서 나의 스킬을 조금더 레벨업 하고자 한다.

IDE : IntelliJ

언어 : Java

DB : MySQL

빌드관리 도구 : Maven

OS : iOS

참고유튜브 : 메타코딩

 


시작하기전 컨트롤러에 해당 기능들을 전부 작성하는건 좋은방법은 아니지만 공부목적으로 좀더 이해하기 편하게 하기위해서

컨트롤러에 작성하고자한다.

 

 

지난글에서 응답받은 토큰의 정보들을 복사해서 table폴더하위로 OAuthToken객체로만든다.

 

값을 주고받아야하기때문에 @Data 어노테이션을 추가해주자

@Data
public class OAuthToken {
    private String access_token;
    private String token_type;
    private String refresh_token;
    private int expires_in;
    private String scope;
    private int refresh_token_expires_in;

}

 

json데이터를 오브젝트에 담아서 사용하기 위해서 userController로 이동해서 아래와 같이 작성한다.

        ObjectMapper objectMapper = new ObjectMapper();
        OAuthToken oAuthToken = null;

        try {
            oAuthToken = objectMapper.readValue(response.getBody(), OAuthToken.class);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

 

이제 accessToken을 이용해서 사용자의 정보를 가져와보자

카카오개발자센터에서 REST API에서 사용자 정보 가져오기를 확인해보면 아래와 같이 토큰을 활용해 사용자정보를 가져오는 방법을 알 수 있다.

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info

 

요청을 위해서 Authorization 과 content-type을 필수로 보내줘야한다.

아래로 내려가보면 우리가 어떤 정보들을 응답받을 수 있는지 확인할 수 있다.

여기서 처음에 우리가 요청하는 정보는 email 뿐이였기 때문에 다른것들은 크게 신경쓰지 않아도 된다.

 

이제 요청하기위해서 다시 userController로 이동해서 아래와 같이 작성한다.

헤더부분에 필수로 요청을 해야했던 Authorization 과 content-type를 넣어준다.

그리고 response2를 리턴해줘서 서버에서 카카오톡 로그인버튼을 눌러주면 응답받은 내용들을 확인할 수 있다.

// 사용자정보 요청
        // http 요청객체생성
        RestTemplate restTemplate2 = new RestTemplate();

        //HttpHedaer 오브적트 생성
        HttpHeaders headers2 = new HttpHeaders();

        headers2.add("Authorization", "Bearer " + oAuthToken.getAccess_token());
        headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");


        //HttpHeader 와 HttpBody를 하나의 오브젝트에 담기
        HttpEntity<MultiValueMap<String, String>> kakaoProfileRequest =
                new HttpEntity<>(headers2);

        //Http 요청하기 post방식 -> response 변수의 응답받음

        ResponseEntity<String> response2 = restTemplate2.exchange(
                "https://kapi.kakao.com/v2/user/me",
                HttpMethod.POST,
                kakaoProfileRequest,
                String.class
        );

 

카카오로그인버튼을 누르면 응답받은 정보들을 확인할 수 있다.

응답받은 정보들을 객체에 넣어서 정리하기 위해서 유저정보들을 복사해서 아래 사이트로 이동한다.

https://www.jsonschema2pojo.org/

 

가지고온 정보들을 복사해놓고 패키지이름과 원하는 클래스이름을 작성하고 스네이크케이스(snack_case)방식을 만들기 위해서 아래에 Property word delimiters를 빈칸으로 만든다.

 

 

미리보기를 눌러서 확인해보면 스네이크케이스로 객체가 생성된걸 확인할 수 있다.

 

table패키지 아래에 KakaoProfile을 생성해서 만들어진 코드를 붙여넣고 정리를 해준다.

 

@JsonIgnoreProperties(ignoreUnknown=true)를 추가해서 주석으로 막은부분이 없더라도 무시하고 사용할수 있게 하였다.

@Data
@JsonIgnoreProperties(ignoreUnknown=true)
public class KakaoProfile {

    public Long id;
    public String connected_at;
    public KakaoAccount kakao_account;

    @Data
    @JsonIgnoreProperties(ignoreUnknown=true)
    public class KakaoAccount {

        /*public Boolean profile_image_needs_agreement;
        public Boolean has_email;
        public Boolean email_needs_agreement;
        public Boolean is_email_valid;
        public Boolean is_email_verified;;*/
        public String email;

    }

}

 

응답받은 정보들을 확인해보기 위해서 userController로 이동해서 위에서 했던 코드를 가지고와서 아래와 같이 수정해서 작성하면

로그인한 유저의 아이디번호와 이메일을 확인할 수 있다.

ObjectMapper objectMapper2 = new ObjectMapper();
        KakaoProfile kakaoProfile = null;

        try {
            kakaoProfile = objectMapper2.readValue(response2.getBody(), KakaoProfile.class);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        System.out.println("카카오 정보 (아이디번호): " + kakaoProfile.getId());
        System.out.println("카카오 정보 (이메일) : " + kakaoProfile.getKakao_account().getEmail());

위에사진과 같이 유저의 정보를 가져올수 있다.

 

비밀번호를 고정된값으로 계속 넣어줘서 회원가입을 자동으로 하게해서 해당유저의 정보를 db에 저장해서 관리하도록 하자

application.yml로 이동해서 원하는 비밀번호를 입력해주자.

실제 서비스에서 해당방식으로 유저들을 관리하지 않겠지만 해당 비밀번호가 노출이 된다면 아이디만 알고 있다면 모든 계정에 로그인할 수있으니 노출하지 않도록 잘 관리를 해야한다.

cos:
  key: 1q2w3e4r

 

userContoller에서 내가 application에 입력한 비밀번호를 사용할수 있게 해준다.

    @Value("${cos.key}")
    private String cosKey;

    @Autowired
    private UserService userService;

    @Autowired
    private AuthenticationManager authenticationManager;

 

우리사이트에서 회원들이 회원가입을 하기 위해선 아이디와 비밀번호 그리고 이메일을 필요로 했다.

그러면 해당 정보들을 객체에 담아서 사용할수 있게 해준다.

아이디는 유저이메일_카카오아이디번호 형식으로

비밀번호는 1q2w3e4r

이메일은 카카오에서 받은 이메일로 kakaoUser에 담아준다.

        User kakaoUser = User.builder()
                .username(kakaoProfile.getKakao_account().getEmail() + "_" + kakaoProfile.getId())
                .password(cosKey)
                .email(kakaoProfile.getKakao_account().getEmail())
                .build();

 

만약 해당유저가 우리사이트에서 로그인을 하게 된다면 우선 db에 해당 유저의 아이디가 저장되어있는지 확인해보고

db에 저장되어있지 않다면 자동으로 유저정보를 db에 저장해서 로그인하게 해주는 기능을 작성할 것이다.

 

회원찾기 메서드를 호출하고 서비스로 이동해서 해당 메서드를 작성하도록 하자

User originUser = userService.회원찾기(kakaoUser.getUsername());

 

유저아이디(username)을 받아서 namingQuery를 활용해 유저아이디를 이용해 db에서 해당유저의 아이디가 존재하는지 확인해보고

만약에 존재하지 않는다면 빈객체를 리턴해준다.



    @Transactional(readOnly = true)
    public User 회원찾기(String username) {

        User user = userRepository.findByUsername(username)
                .orElseGet(()->{
                    return new User();
                });

        return user;
    }

 

그 후 컨트롤러에서 콘솔에서 확인해보면 이미 가입된 유저라면 유저의 아이디가 아니라면 Null값을 받을 수 있다.

이미 가입된 유저라면 유저의 아이디
아니면 null값을 받을 수 있다.

 

그렇게 null값을 받는다면 해당유저는 db에 없는 유저이므로 회원가입을 진행해주면 된다.

userService에서 이전에 작성했었던 회원가입 메서드를 사용하면 된다.

        if (originUser.getUsername() == null) {
            userService.회원가입(kakaoUser);
        }

 

그렇면 카카오로그인버튼을 누른다면 기존의 있던 사용자든 새로운 사용자든 db에 해당 사용자의 정보가 있을 것이고 

해당 정보들로 로그인처리를 해주면 된다.

기존 내정보수정에 있던 코드를 가져와서 수정해서 사용해주면 된다.

Authentication authentication =
                authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(kakaoUser.getUsername(), cosKey));
        SecurityContextHolder.getContext().setAuthentication(authentication);

 

그런데 나는 여기서 카카오로그인을 하면 해당유저의 정보를 가져와서 db에 저장까지 되는데 자동 로그인처리가 되지 않아서

해당 부분을 해결하는대로 다시 글을 작성할 예정이다.

댓글