그린 라이프 팁

SpringBoot 3.0^ + JPA + QueryDSL 5.0^ + Security 설정 본문

기술

SpringBoot 3.0^ + JPA + QueryDSL 5.0^ + Security 설정

요요키 2023. 7. 22. 17:15

삽질을 너무 많이 했고, chatgpt나 인터넷 검색 자료는 모두 죄다 어뎁터 방식으로 붙이는 식이더라 그래서 아에 그냥

내가 해보고 정리하자는 차원에서 공개합니다. 모두 삽질 없이 편안하게 짜시길 바랍니다.

gradle 설정

// 1. queryDsl version 정보 추가
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
    // 2. querydsl plugins 추가
//    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
    id 'java'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

group = 'com.shop'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    // === QueryDsl 시작 ===
    // https://velog.io/@juhyeon1114/Spring-QueryDsl-gradle-%EC%84%A4%EC%A0%95-Spring-boot-3.0-%EC%9D%B4%EC%83%81

    // == 스프링 부트 3.0 미만 ==
//    implementation 'com.querydsl:querydsl-jpa'
//    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"

    // ⭐ Spring boot 3.x이상에서 QueryDsl 패키지를 정의하는 방법
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
    annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"

    // === QueryDsl 끝 ===

    // thyemleaf laout dialect dependency 추가하기
    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

    // security dependency 추가하기
    implementation 'org.springframework.boot:spring-boot-starter-security'

    // validation dependency 추가하기
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    // DevTools 추가
    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

// === ⭐ QueryDsl 빌드 옵션 (선택) ===
def querydslDir = "$buildDir/generated/querydsl"

sourceSets {
    main.java.srcDirs += [ querydslDir ]
}

tasks.withType(JavaCompile) {
    options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}

clean.doLast {
    file(querydslDir).deleteDir()
}

Security Config 설정

package com.shop.shop.config;


import com.shop.shop.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    MemberService memberService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        RequestMatcher requestMatcher = new AntPathRequestMatcher("/members/new");
        http
                .authorizeHttpRequests(auth->auth.requestMatchers(new AntPathRequestMatcher("/css/**")).permitAll()) // static 파일 접근 허용
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(requestMatcher).permitAll() // 회원가입페이지 허용
                        .anyRequest()
                        .authenticated()
                )
                .formLogin(formLogin -> formLogin
                        .loginPage("/members/login") // 로그인페이지 연결
                        .defaultSuccessUrl("/") // 로그인 성공시 메인페이지 이동 
                        .permitAll() // 해당 두 패스는 무조건 진입허용 이게 빠지면 무한루프 
                        .usernameParameter("email")
                        .failureUrl("/members/login/error")
                )

                .logout(logout -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/members/logout"))
                        .logoutSuccessUrl("/")
                );

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return memberService;
    }

    //    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new SimplePasswordEncoder();
    }

}