리눅스/Window10 Arch Linux

Window 10 Intellij Maven으로 생성한 SpringBoot 프로젝트 카카오 로그인 만들기

차세대 IT 리더 비공자 2024. 8. 28. 21:25

 

목록

1. 카카오 로그인 버튼 만들기

2. loginForm.jsp

3. Application.properties.java

4. UserController.java

5. UserService.java

6. UserMapper.java

7. UserMapper.xml

8. 실제 로그인 시, DRESS_CODE DB저장

 

 

 

1. 카카오 로그인 버튼 만들기

도구 탭으로 이동 후, 리소스 다운로드 클릭

 

다운로드( .png )버튼 클릭

 

2. loginForm.jsp

<!-- 카카오 로그인 -->
<form action="/kakaoLogin" method="post">
<!-- 카카오 버튼 이미지 다운로드 
     경로 : https://developers.kakao.com/docs/latest/ko/kakaosync/design-guide#kakaosync-button-standard-->
  <button type="submit" 
          style="background-image:url(/resources/images/kakao_login.png); 
                width: 90px; height: 45px; solid-color: yellow">
  </button>
</form>

 

 

3. Application.properties.java

카카오 로그인 Redirect URL ( 카카오 로그인 시, 후 처리 )

로컬 서버 : localhost:8080 ( 윈도우 환경 내장 Tomcat )

원격 서버 : 192.168.1.149:8080 ( Linux 환경 원격 Tomcat )

 

카카오 로그아웃 Redirect URL ( 카카오 로그인 시, 후 처리 )

로컬 서버 : localhost:8080 ( 윈도우 환경 내장 Tomcat )

원격 서버 : 192.168.1.149:8080 ( Linux 환경 원격 Tomcat )

 

 

 

 

# ==========================================
# = 카카오 REST_API KEY
# ==========================================
# PRD환경 카카오 REST_API KEY
# kakao.rest-api-key=36c77bcc532c7f0124187c491c87efe0

# DEV환경 카카오 REST_API KEY
kakao.rest-api-key=1ed813761eb60cf06df6f066f437aa2c


# ==========================================
# = 카카오 Redirect URI
# ==========================================
# PRD환경 카카오 Redirect URI
# kakao.redirect-uri=http://192.168.1.149:8080/kakaoLoginCallBack

# DEV환경 카카오 Redirect URI
kakao.redirect-uri=http://localhost:8080/kakaoLoginCallBack


# ==========================================
# = 카카오 Logout Redirect URI
# ==========================================
# PRD환경 카카오 Logout Redirect URI
# kakao.logout.redirect.uri=http://192.168.1.149:8080/kakaoLogout

# DEV환경 카카오 Logout Redirect URI
kakao.logout.redirect.uri=http://localhost:8080/kakaoLogout

 

 

4. UserController.java

loginForm.jsp 화면에서 카카오 로그인 버튼을 클릭 시

/kakaoLogin을 Post방식으로 요청합니다.

@Controller
@Slf4j
public class UserController {

    // UserService Been을 찾아준다.
    @Autowired
    UserService userService;

    // 카카오 REST_API KEY
    // @Value 어노테이션에 application.properties에 설정된 키값 입력
    @Value("${kakao.rest-api-key}")
    private String kakaoRestApiKey;

    // 카카오 Redirect URI
    @Value("${kakao.redirect-uri}")
    // @Value 어노테이션에 application.properties에 설정된 키값 입력
    private String kakaoRedirectUri;

    // 카카오 계정 로그아웃 시, Redirect 받을 URL
    // @Value 어노테이션에 application.properties에 설정된 키값 입력
    @Value("${kakao.logout.redirect.uri}")
    private String kakaoLogoutRedirectUri;
    
    
    // 카카오 로그인
    @PostMapping("/kakaoLogin")
    public String kakaoLogin() {
        // 카카오 로그인 페이지로 리다이렉트하기 위한 URL을 생성합니다.
        String kakaoLoginUrl =
        "https://kauth.kakao.com/oauth/authorize?client_id=" + kakaoRestApiKey     // REST API 키를 URL에 포함합니다.
        + "&redirect_uri=" + kakaoRedirectUri     // 로그인 후, 돌아올 Redirect URI를 URL에 포함합니다.
        + "&response_type=code";                  // 인가 코드 요청을 위한 response_type 입니다.

        // developer.kakao에 등록된 리다이렉트 주소
        // 로컬 서버 리다이렉트 연결 : http://localhost:8080/kakaoLoginCallBack
        // 원격 서버 리다이렉트 연결 : http://192.168.1.149:8080/kakaoLoginCallBack
        // 리다이렉트 요청으로 아래의 kakaoLoginCallBack 메서드 호출
        return "redirect:"+kakaoLoginUrl;
    }

    // RedirectCallback 메서드는 GET방식으로만 요청이 가능
    @GetMapping("/kakaoLoginCallBack")
    public String kakaoLoginCallBack(@RequestParam("code") String code, Model model, HttpSession session) {
        // RestTemplate 객체를 생성합니다. HTTP 요청을 보내기 위해 필요합니다.
        RestTemplate restTemplate = new RestTemplate();

        // 카카오로부터 액세스 토큰을 요청할 URL을 설정합니다.
        String tokenUrl = "https://kauth.kakao.com/oauth/token";

        // 액세스 토큰 요청에 필요한 파라미터를 담을 MultiValueMap을 생성합니다.
        MultiValueMap<String, String> tokenParams = new LinkedMultiValueMap<>();
        tokenParams.add("grant_type", "authorization_code"); // OAuth 2.0 인증 방식으로 authorization_code를 사용합니다.
        tokenParams.add("client_id", kakaoRestApiKey); // 카카오 REST API 키를 전달합니다.
        tokenParams.add("redirect_uri", kakaoRedirectUri); // 리다이렉트 URI를 설정합니다.
        tokenParams.add("code", code); // 카카오에서 반환한 인가 코드를 전달합니다.

        // 요청 헤더를 설정합니다. Content-Type을 application/x-www-form-urlencoded로 설정합니다.
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        // 요청 본문을 설정합니다. 본문에 파라미터를 포함시킵니다.
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(tokenParams, headers);

        try {
            // POST 요청을 보내서 액세스 토큰을 받습니다.
            ResponseEntity<Map> tokenResponse = restTemplate.postForEntity(tokenUrl, request, Map.class);

            // 응답에서 액세스 토큰을 추출합니다.
            String accessToken = (String) tokenResponse.getBody().get("access_token");

            // 액세스 토큰을 사용하여 사용자 정보를 요청할 URL을 설정합니다.
            String userInfoUrl = "https://kapi.kakao.com/v2/user/me";

            // 사용자 정보 요청 시 헤더에 Authorization을 추가합니다. 
            // Bearer 인증 방식으로 액세스 토큰을 헤더에 추가합니다.
            HttpHeaders userHeaders = new HttpHeaders();
            userHeaders.set("Authorization", "Bearer " + accessToken);
            HttpEntity<String> userRequest = new HttpEntity<>(userHeaders);

            // GET 요청을 보내서 사용자 정보를 받습니다.
            ResponseEntity<Map> userResponse = 
            restTemplate.exchange(userInfoUrl, HttpMethod.GET, userRequest, Map.class);

            // 응답에서 사용자 정보를 추출합니다.
            Map<String, Object> kakaoAccount = 
            (Map<String, Object>) userResponse.getBody().get("kakao_account");
            
            // developer.kakao에서 로그인 동의항목 선택내용을 가져옵니다.
            // 사용자 정보를 추출하여 UserDTO 객체를 생성합니다.
            String userName = ((Map<String, String>) kakaoAccount.get("profile")).get("nickname");
            String userId = userResponse.getBody().get("id").toString();
            // String userEmail = kakaoAccount.get("email").toString();

            UserDTO userDTO = new UserDTO();
            userDTO.setUserName(userName);  // 사용자 이름 설정  ( 동의항목 )
            userDTO.setUserId(userId);      // 사용자 ID 설정    ( 동의항목 )

            // UserDTO 객체를 데이터베이스에 저장합니다.
            userService.kakaoSave(userDTO);

            // 사용자 정보를 모델에 추가하여 JSP 페이지에서 사용할 수 있도록 합니다.
            session.setAttribute("userName", userName);
            session.setAttribute("userId", userId);
            model.addAttribute("userName", userDTO.getUserName());

            // 홈 페이지로 리다이렉트합니다. 로그인 후 사용자 정보를 보여줄 페이지로 이동합니다.
            return "redirect:"+"/";
        } catch (HttpClientErrorException e) {
            // HTTP 오류가 발생한 경우, 오류 코드와 응답 본문을 출력합니다.
            System.out.println("HTTP Error: " + e.getStatusCode());
            System.out.println("Response Body: " + e.getResponseBodyAsString());

            // 에러가 발생한 경우, 에러 페이지로 리다이렉트합니다.
            return "error";
        }
    }

    // 유저 로그아웃
    @PostMapping("/logout")
    public String userLogout(HttpSession session) {

        // 카카오 로그아웃
        String userId = (String)session.getAttribute("userId");
        if(userId == null) {
            // 세션에 담긴 정보 정리
            session.invalidate();
            return "redirect:" + "/loginForm";
        }else {
            // 카카오 로그아웃 API 호출
            String kakaoLogoutUrl = "https://kauth.kakao.com/oauth/logout"
                    + "?client_id=" + kakaoRestApiKey
                    + "&logout_redirect_uri=" + kakaoLogoutRedirectUri;
                    // 세션에 담긴 정보 정리
                    session.invalidate();
            return "redirect:" + kakaoLogoutUrl;
        }

    }

    @GetMapping("/kakaoLogout")
    public String kakaoLogOutSeccess() {
            System.out.println("카카오 계정 로그아웃 성공!");
            return "redirect:" + "/loginForm";
    }

 

 

5. UserService.java

package com.rnbsoft.dress_code.service;

import com.rnbsoft.dress_code.dto.UserDTO;
import com.rnbsoft.dress_code.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Service
@Transactional
public class UserService {

    @Autowired
    private UserMapper userMapper;

    // 카카오 로그인 시, 유저 정보 저장 ( 이름과 ID(인가코드 값) )
    public void kakaoSave(UserDTO userDTO) {
        userMapper.kakaoSave(userDTO);
    }
}

 

 

6. UserMapper.java

package com.rnbsoft.dress_code.mapper;
import com.rnbsoft.dress_code.dto.UserDTO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

@Mapper
public interface UserMapper {

    // 카카오 로그인
    void kakaoSave(UserDTO userDTO);
}

 

 

7. UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.rnbsoft.dress_code.mapper.UserMapper">

        <!-- MyBatis 2차 캐시 사용  -->
        <cache eviction="LRU" flushInterval="30000" size="512" readOnly="true"/>

        <!-- 카카오 로그인 회원가입 -->
        <insert id="kakaoSave" parameterType="UserDTO" flushCache="true">
            INSERT INTO TB_USERS
            ( USER_NAME, USER_ID, USER_EMAIL, SOCIAL_YN )
            VALUES( #{userName}, #{userId}, 'kakaoLogin@rnbsoft.com', 'Y' )
        </insert>
</mapper>

 

 

8. 실제 로그인 시, DRESS_CODE DB저장

카카오톡 계정 로그인 : SOCIAL_YN = "Y"

DRESS 계정 로그인 : SOCIAL_YN = NULL

테이블에 적재 됩니다.

 

 

카카오 로그인 화면

카카오 로그아웃 화면