SpringBoot - OAuth2 로 카카오 로그인 (2) DB저장,메인화면이동, 로그아웃(세션종료) 추가

2024. 5. 14. 09:56Full Stack Course 풀스택과정/SPRING

728x90

배울내용:

OAuth2 실행테스트

OAuth2 카카오 로그인

스프링부트 OAuth2 

SpringBoot OAuth2

카카오 로그인 만들기

kakao 로그인 

카카오 로그인 연동

카카오 로그인 DB저장

카카오 로그인후 메인화면이동

OAuth 뷰 구성

 

 

 

 

 

 

 

지난 1편에서 부터 이어집니다

 

https://sarimus.tistory.com/130

 

SpringBoot - OAuth2 로 카카오 로그인

배울내용:OAuth2 실행테스트OAuth2 구글 로그인스프링부트 OAuth2 SpringBoot OAuth2카카오 로그인 만들기kakao 로그인 카카오 로그인 연동액세스 토큰 만들기인증 관련 설정값OAuth 뷰 구성  이번 포스팅

sarimus.tistory.com

 

 

 

 

 

먼저 email은 kakao developers 에 동의항목에 보면 선택할수가없다 ! 

 

 

 

이메일을 로그인 시, 필수 동의로 설정하려면 비즈앱 전환이 필요합니다.

 

디벨로퍼스 앱에 사업자 정보를 입력하고 비즈 앱으로 설정해야한다 .

비즈 앱으로 설정할 경우, 개인정보 항목 중 이메일을 '연결 시 필수’로 설정할 수 있고 같은 사업자 번호로 인증된 프로필(플러스친구)과 연결할 수 있으며 서브 도메인, 친구 API등 추가 권한을 신청할 수 있습니다.

비즈 앱은 아래의 경로에서 진행할 수 있습니다.

[내 애플리케이션] > [앱 설정] > [비즈니스] > [비즈 앱 정보 ]> [사업자 정보 등록]

비즈 앱에 관한 정보는 가이드에서도 확인하실 수 있다.

 

그렇게 설정하면 아래처럼 선택할수가 있다 

 

 

 

 

 

 

 

 

이후에 이전에 써놨던 SecurityConfig 에 있는

successHandler

 

성공핸들러에 보면  아래 처럼 id 값만 받아왔다 

 

 

 

    @Bean
    public AuthenticationSuccessHandler successHandler() {
        return ((request, response, authentication) -> {
            DefaultOAuth2User defaultOAuth2User = (DefaultOAuth2User) authentication.getPrincipal();

            String id = defaultOAuth2User.getAttributes().get("id").toString();
            // 이메일 주소를 찾았을 때만 값을 추출하여 사용
            if (matcher.find()) {
                email = matcher.group();
            }
            String body = """
                    {"id":"%s"}
                    """.formatted(id);

            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());


            PrintWriter writer = response.getWriter();
            writer.println(body);
            writer.flush();
        });
    }

 

 

 

그러면 여기서 email을 추가해주면 된다 

 

 

 

 

 

    @Bean
    public AuthenticationSuccessHandler successHandler() {
        return ((request, response, authentication) -> {
            DefaultOAuth2User defaultOAuth2User = (DefaultOAuth2User) authentication.getPrincipal();

            String id = defaultOAuth2User.getAttributes().get("id").toString();
            String email = defaultOAuth2User.getAttributes().get("kakao_account").toString();

            // 이메일 주소를 찾았을 때만 값을 추출하여 사용
            if (matcher.find()) {
                email = matcher.group();
            }
            String body = """
                    {"id":"%s",
                     "email":"%s"}
                    """.formatted(id,email);

            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

        });
    }

 

(kakao_account 부분 이나 id 는 kakaoDeveloper 에서 확인할수있음)

그러면 login 에서 카카오 로그인을 하게 되면 아래처럼 보이게 된다 

 

 

 

 

 

 

그런데 우리는 이부분이 다필요한게 아니라 angrybird24@naver.com 만 필요하다

그래서 간단하게 정규표현식으로 잘라서 넣어줬다 

 

 

 

 

//앞코드 무시.. 

            String id = defaultOAuth2User.getAttributes().get("id").toString();
            String email = defaultOAuth2User.getAttributes().get("kakao_account").toString();

            String regex = "\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(email);
            // 이메일 주소를 찾았을 때만 값을 추출하여 사용
            if (matcher.find()) {
                email = matcher.group();
            }
            String body = """
                    {"id":"%s",
                     "email":"%s"}
                    """.formatted(id,email);

            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
 

            PrintWriter writer = response.getWriter();
            writer.println(body);
            writer.flush();
 
        });
    }

 

 

 

 

 

그렇게하면 이제 더이상 다른 필요없는게 없고

 

 

이렇게 id 와 email 값만 받아오게된다

 

그럼이제 이 불러온값을 DB에 저장해보자 

 

 

 

 

 

DB(MySql) 에 저장하기 

추가적으로 로그인 성공시 메인페이지 이동까지 해볼것이다 

 

 

 

 

 

먼저 package 를 entity 만든뒤에 User 를 만들고 아래처럼 쓴다 

 

 

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name = "pet")
public class User {
    @Id
    private String email;

    @Column
    private String id;
}

 

 

필자는 email 를 (PK primary Key) 로 뒀지만 id 로 PK 로 해도 상관없다

 

 

 

 

 

 

그다음 repository 패키지를 만든뒤에 UserRepository 를 만들고 아래처럼 작성해주자 

 


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

public interface UserRepository extends JpaRepository<User, Long> {
    // 추가적인 메서드가 필요하다면 여기에 정의할 수 있습니다.
}

 

 

 

 

 

그리고 service 패키지를 만든뒤에 UserService 를 만들고 아래처럼 작성해주자

 

 

import com.codehows.animalcafe.entity.User;
import com.codehows.animalcafe.repository.UserRepository;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }


    public void saveUserFromJson(String email,String id) {
        User user = new User();
        user.setEmail(email);
        user.setId(id);
        userRepository.save(user);
    }
}

 

 

그리고 successHandler로 돌아와 

 

 

//이전코드 생략..


            String body = """
                    {"id":"%s",
                     "email":"%s"}
                    """.formatted(id,email);

            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

            //db에 저장
            userService.saveUserFromJson(email,id);

//            PrintWriter writer = response.getWriter();
//            writer.println(body);
//            writer.flush();


            // 로그인 성공시 메인페이지 이동
            response.sendRedirect("/login/main");

 

PrintWriter 코드는 주석처리해주고 

DB저장하는것과 login 페이지를 만들어주자 

 

 

 

그리고는 LoginController에서 /main 을 추가해주자

 

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
@RequestMapping("/login") //url 입력
public class LoginController {
    @GetMapping
    public String login(){
        return "login";
    }


    @GetMapping("/main")
    public String loginPage() {
        return "main";
    }

}

 

 

그뒤에 Templates 패키지에 main.html 을 만든뒤에 아래처럼 만들고

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Success</title>
</head>
<body>
<h1>Login Successful!</h1>
<p>Welcome to SARIMUS Animal Cafe!</p>
</body>
</html>

 

 

 

실행하면 

 

 

 

 

성공적으로 로그인된다 

 

 

그리도 DB 에 확인해보면 로그인 성공시에 메인화면으로 이동함과 동시에 db에 저장해준다

 

 

 

참고로 만약 같은 로그인 시켜줄시 if 문을  따로 만들어 같은 값이 안들어가거나 중복값이 안들어가게 하렸는데

알아서  잘 들어가졌다  

 

 

 

만약 세션을 넣고싶으면 
Controller 에 loginPage 부분에 아래처럼 수정하고

 


@GetMapping("/main")
public String loginPage(HttpSession session, Model model) {
    String userId = (String) session.getAttribute("userId");
    String userEmail = (String) session.getAttribute("userEmail");

    //세션정보 확인
    model.addAttribute("userId", userId);
    model.addAttribute("userEmail", userEmail);

    return "main";
}

 

 

 

SecurityConfig에 SuccessHandler 에다가도 아래를 추가한다



            // 세션에 사용자 정보 저장
            HttpSession session = request.getSession();
            session.setAttribute("userId", id);
            session.setAttribute("userEmail", email);

 

 

그리고 로그인 성공창 html에 thymeleaf 를 추가하고 아까 Controller에서 모델에 추가했던

userId 와 userEmail 을 출력하는코드를 추가해준뒤에 실행하면 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Success</title>
</head>
<body>
<h1>Login Successful!</h1>
<p>Welcome to SARIMUS Animal Cafe!</p>



<h1>Session Information</h1>
<div>
    <p><strong>User ID:</strong> <span th:text="${userId}"></span></p>
    <p><strong>User Email:</strong> <span th:text="${userEmail}"></span></p>
</div>
</body>
</html>

 

 

아래처럼 보이게되면 성공이다 

 

 

 

 

 

 

 

로그아웃 (세션종료)

간단하다 SecurityFilter에 http.logout 을 만들어준다음에

logoutUrl 를 설정해주고

logoutSuccessUrl 로 로그아웃 성공시 /login 페이지로 다시이동시켜준뒤에

.deleteCookies 로 세션을 삭제한다 


public SecurityConfig(OAuth2UserService oAuth2UserService) {
    this.oAuth2UserService = oAuth2UserService;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .csrf((csrf) ->
                    csrf.disable()
            );
    http.authorizeHttpRequests(config -> config.anyRequest().permitAll());
    http.oauth2Login(oauth2Configurer -> oauth2Configurer
            .loginPage("/login")
            .successHandler(successHandler())
            .userInfoEndpoint(userInfo -> userInfo
                    .userService(oAuth2UserService)));

    http.logout(logout ->
            logout
                    .logoutUrl("/logout") // 로그아웃 URL 설정
                    .logoutSuccessUrl("/login") // 로그아웃 성공 후 리다이렉트할 URL 설정
                    .invalidateHttpSession(true)
                    .deleteCookies("JSESSIONID")
    );
    return http.build();
}

 

 

 

 

그리고 로그아웃 버튼을 메인페이지에서 추가하면 된다

 

 


<!-- 로그아웃 버튼 -->
<form action="/logout" method="post">
    <button type="submit">Logout</button>
</form>

 

 

 

그러면 기존에 "JSESSIONID" 가 있던게 없어져있는걸 볼수가 있다 

 

 

 

 

 

kakaoLogin .zip
0.14MB

728x90