Spring Boot/[Spring boot] 개발

[Spring boot] users 데이터베이스 생성과 로그인

재윤 2025. 1. 5. 16:31
반응형
  • 카카오 로그인을 한 후 응답값을 고민을 좀 해봐야한다.

postgreSQL문으로 User table을 만들어보자

 

  • PostgreSQL에서 User → 예약어라서 Users로 하던지 “User”로 해야됨
 create table User(user_id INT auto_increment, email VARCHAR(100) not null, nickname VARCHAR(100) not null, profile VARCHAR(2000), primary key(user_id));
ERROR:  syntax error at or near "User"
LINE 1: create table User(user_id INT auto_increment, email VARCHAR(...

 

User 클래스 이지만 테이블에 실제 이름은 users임

package com.Kkrap.Entity;

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

import java.util.List;

@Getter
@Entity
@Table(name = "users")
public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;

    @Setter
    @Column(nullable = false)
    private String email;

    @Setter
    @Column(nullable = false)
    private String nickname;

    @Setter
    @Column(nullable = false)
    private String profile;

    @Setter
    @Column(nullable = false)
    private Long kakaoId;

    // Links와의 관계 추가
    @OneToMany(mappedBy = "users", cascade = CascadeType.ALL)
//    @JsonIgnore // 순환 참조 방지
    private List<Links> links;

    @Builder
    public Users(String email, String nickname, String profile, Long kakaoId)
    {
        this.email = email;
        this.nickname = nickname;
        this.profile = profile;
        this.kakaoId = kakaoId;
    }

    public Users() {
        // 기본 생성자
    }
}

만약 jpa가 자동으로 쿼리문을 해주지 않으면 → application에 넣어주자

spring.jpa.hibernate.ddl-auto=update

이제 사용자의 정보를 DB안에 넣어보자.

UsersRepository

package com.Kkrap.Repository;

import com.Kkrap.Entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UsersRepository extends JpaRepository<Users, Long>{
//    @Query("SELECT userId from Users Where kakaoId = :kakaoId")
    @Query("SELECT u FROM Users u WHERE u.kakaoId = :kakaoId")
    Optional<Users> findByKaKaoId(@Param("kakaoId") Long kakaoId);

}

SecurityConfig.java

package com.Kkrap.Security;

import com.Kkrap.Entity.Users;
import com.Kkrap.Repository.UsersRepository;
import com.Kkrap.Service.CustomOAuth2UserService;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;

@Configuration
@EnableMethodSecurity
public class SecurityConfig {
    @Autowired
    private UsersRepository usersRepository;

    private final CustomOAuth2UserService oAuth2UserService;

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

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .cors(cors -> cors.configurationSource(corsConfigurationSource())) // CORS 설정 추가
                .csrf(csrf -> csrf.disable()) //
                .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll()
                )
                .oauth2Login(oauth2 -> oauth2
                        .loginPage("/login")
                        .userInfoEndpoint(userInfo -> userInfo
                                .userService(oAuth2UserService)
                        )
                        .successHandler(authenticationSuccessHandler())  // 로그인 성공 시 핸들러 사용
                );

        return http.build();
    }
    // CORS 설정
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Collections.singletonList("<http://172.20.10.12:3000>")); // 프론트엔드 주소 허용
        configuration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(), HttpMethod.DELETE.name()));
        configuration.setAllowCredentials(true); // 쿠키 및 인증 정보 허용
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                Object principal = authentication.getPrincipal();
                if (principal instanceof DefaultOAuth2User) {
                    DefaultOAuth2User defaultOAuth2User = (DefaultOAuth2User) principal;

                    // 카카오 사용자 정보 추출
                    Map<String, Object> attributes = defaultOAuth2User.getAttributes();

                    String kaka_id = attributes.get("id").toString(); // 사용자 ID
                    Map<String, Object> kakaoAccount = (Map<String, Object>) attributes.get("kakao_account");
                    Map<String, Object> profile = (Map<String, Object>) kakaoAccount.get("profile");

                    String nickname = profile.get("nickname").toString(); // 사용자 닉네임
                    String profileImage = profile.get("profile_image_url").toString(); // 프로필 이미지 URL
                    String email = kakaoAccount.get("email").toString(); // 이메일

                    // 디버그용 로그 출력
                    System.out.println("카카오 사용자 ID: " + kaka_id);
                    System.out.println("카카오 사용자 닉네임: " + nickname);
                    System.out.println("카카오 사용자 이메일: " + email);
                    System.out.println("카카오 사용자 프로필 이미지 URL: " + profileImage);

                    // 사용자 정보를 각각 쿠키에 저장
                    setCookie(response, "kakao_id", kaka_id, 7 * 24 * 60 * 60); // 쿠키 유효기간 7일
                    setCookie(response, "nickname", nickname, 7 * 24 * 60 * 60);
                    setCookie(response, "profileImage", profileImage, 7 * 24 * 60 * 60);
                    setCookie(response, "email", email, 7 * 24 * 60 * 60);

                    //DB 로직 추가
                    String userId;
                    Optional<Users> CheckUser = usersRepository.findByKaKaoId(Long.valueOf(kaka_id));
                    System.out.println("CheckUser : " + CheckUser);
                    if (CheckUser.isEmpty()){
                        Users newUser = new Users(email, nickname, profileImage, Long.valueOf(kaka_id));
                        usersRepository.save(newUser);
                        setCookie(response, "userId", String.valueOf(newUser.getUserId()), 7 * 24 * 60 * 60);
                        userId = String.valueOf(newUser.getUserId());
                    }
                    else
                    {
                        Users existingUser = CheckUser.get();
                        setCookie(response, "userId", String.valueOf(existingUser.getUserId()), 7 * 24 * 60 * 60);
                        userId = String.valueOf(existingUser.getUserId());
                    }

                    // 사용자 정보를 URL 인코딩
                    String redirectUrl = String.format(
                            "<http://localhost:3000/login/success?kakao_id=%s&nickname=%s&profileImage=%s&email=%s&userId=%s>",
                            URLEncoder.encode(kaka_id, tandardCharsets.UTF_8.toString()),
                            URLEncoder.encode(nickname, StandardCharsets.UTF_8.toString()),
                            URLEncoder.encode(profileImage, StandardCharsets.UTF_8.toString()),
                            URLEncoder.encode(email, StandardCharsets.UTF_8.toString()),
                            URLEncoder.encode(userId, StandardCharsets.UTF_8.toString())
                    );

                    // 리디렉션
                    response.sendRedirect(redirectUrl);

                } else {
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid user principal type");
                }
            }
        };
    }
    private void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        cookie.setHttpOnly(false); // JavaScript에서 접근 가능하도록 설정
        cookie.setSecure(false); // HTTPS가 아닌 경우에도 전송되도록 설정
        cookie.setDomain("43.203.234.0"); // 도메인을 프론트엔드 주소로 설정
        response.addCookie(cookie);
    }

}

 

DB 확인

반응형