From b27b9ff60f5194f6d46b924572f53a2fcb39ebde Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Sat, 5 Oct 2024 19:15:51 +0900 Subject: [PATCH] =?UTF-8?q?security=20=EC=B6=94=EA=B0=80=20=EC=83=88?= =?UTF-8?q?=EB=A1=9C=EC=9A=B4=20=EC=82=BD=EC=A7=88=20=EA=B1=B0=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 +- .../back/lun/configs/SecurityConfig.kt | 103 ++++++++++++++++++ .../lunaticbum/back/lun/controllers/Owner.kt | 5 + .../back/lun/controllers/UserController.kt | 7 +- .../kr/lunaticbum/back/lun/model/User.kt | 51 ++++++++- .../back/lun/service/UserDetailsService.kt | 8 ++ src/main/resources/application.properties | 10 +- src/main/resources/templates/user/join.html | 3 +- 8 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt create mode 100644 src/main/kotlin/kr/lunaticbum/back/lun/controllers/Owner.kt create mode 100644 src/main/kotlin/kr/lunaticbum/back/lun/service/UserDetailsService.kt diff --git a/build.gradle.kts b/build.gradle.kts index 1fe0718..7312af5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,7 +41,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") - + implementation("org.springframework.boot:spring-boot-starter-security") compileOnly("org.projectlombok:lombok") runtimeOnly("org.mariadb.jdbc:mariadb-java-client") annotationProcessor("org.projectlombok:lombok") diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt b/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt new file mode 100644 index 0000000..3a8fcb4 --- /dev/null +++ b/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt @@ -0,0 +1,103 @@ +package kr.lunaticbum.back.lun.configs + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import kr.lunaticbum.back.lun.model.Role +import kr.lunaticbum.back.lun.utils.LogService +import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.disable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.security.servlet.PathRequest +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpMethod +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.access.AccessDeniedHandler +import org.springframework.web.ErrorResponse + + +@Configuration +@EnableWebSecurity +class SecurityConfig { + @Autowired + lateinit var logService: LogService + + + @Bean + fun filterChain(http: HttpSecurity): SecurityFilterChain { + + http.csrf { + it.ignoringRequestMatchers("/user/joinUser.ajax").disable() + } + http.cors { it.disable() } + http.headers { + it.frameOptions { frameOptionsConfig -> + frameOptionsConfig.disable() + } + } + http.authorizeHttpRequests { + logService.log(it.toString()) + it.requestMatchers(HttpMethod.POST,"/user/**").permitAll() +// it.requestMatchers("/", "/user/**").permitAll() +// .requestMatchers(".ajax").permitAll() +// it.requestMatchers("/", "/user/joinUser.api").permitAll() +// it.requestMatchers("user/joinUser.api").permitAll() + it.anyRequest().permitAll() +// .requestMatchers("/", "/login/**").permitAll() +// .requestMatchers("/posts/**", "/api/v1/posts/**").hasRole(Role.USER.name) +// .requestMatchers("/admins/**", "/api/v1/admins/**").hasRole(Role.ADMIN.name) +// .anyRequest().authenticated() + } + http.sessionManagement { + it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) + } + .exceptionHandling { it -> + it.authenticationEntryPoint(unauthorizedEntryPoint) + .accessDeniedHandler(accessDeniedHandler) + } +// .formLogin { formLogin -> +// formLogin +// .loginPage("/user/join") +////// .usernameParameter("username") +////// .passwordParameter("password") +// .loginProcessingUrl("/user/joinUser.api") +// .defaultSuccessUrl("/", true) +// } + + return http.build() + } + + private val unauthorizedEntryPoint = + AuthenticationEntryPoint { request: HttpServletRequest?, response: HttpServletResponse, authException: AuthenticationException? -> + val fail: ErrorResponse = ErrorResponse.create( Throwable("아직 못들어와"), + HttpStatus.UNAUTHORIZED, "Spring security unauthorized..." + ) + response.status = HttpStatus.UNAUTHORIZED.value() + val json = ObjectMapper().writeValueAsString(fail) + response.contentType = MediaType.APPLICATION_JSON_VALUE + val writer = response.writer + writer.write(json) + writer.flush() + } + + private val accessDeniedHandler = + AccessDeniedHandler { request: HttpServletRequest?, response: HttpServletResponse, accessDeniedException: AccessDeniedException? -> + val fail: ErrorResponse = ErrorResponse.create( Throwable("아직 못들어와"), + HttpStatus.FORBIDDEN, "Spring security forbidden..." + ) + response.status = HttpStatus.FORBIDDEN.value() + val json = ObjectMapper().writeValueAsString(fail) + response.contentType = MediaType.APPLICATION_JSON_VALUE + val writer = response.writer + writer.write(json) + writer.flush() + } +} \ No newline at end of file diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/Owner.kt b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/Owner.kt new file mode 100644 index 0000000..84b7edf --- /dev/null +++ b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/Owner.kt @@ -0,0 +1,5 @@ +package kr.lunaticbum.back.lun.controllers + +class Owner { + +} \ No newline at end of file diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt index 945fabb..0af24f9 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt @@ -44,7 +44,7 @@ class UserController { @ResponseBody - @PostMapping("joinUser.api") + @PostMapping("/joinUser.ajax") fun joinUser(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity { logService.log("${httpServletRequest.requestURI}") logService.log(jsonString) @@ -75,7 +75,10 @@ class UserController { } logService.log(fullData.joinToString("")) var user = Gson().fromJson(fullData.joinToString(""), User::class.java) - var u = userManager.save(user).block() + var u : User? = null + if (user.checkValid()) { + u = userManager.save(user).block() + } val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(ResponceResult().apply { resultCode = if (u != null) 0 else 8245 resultMsg = if (u != null) "OK" else "User Insert Fail" diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt b/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt index 78362e0..16bbec7 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt @@ -1,19 +1,23 @@ package kr.lunaticbum.back.lun.model +import jdk.jfr.Description +import kotlinx.coroutines.reactive.awaitFirst +import kotlinx.coroutines.reactive.awaitFirstOrElse import kr.lunaticbum.back.lun.utils.LogService -import lombok.AllArgsConstructor -import lombok.Data -import lombok.NoArgsConstructor +import lombok.* import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Primary import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document import org.springframework.data.mongodb.repository.Query import org.springframework.data.mongodb.repository.ReactiveMongoRepository +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.stereotype.Repository import org.springframework.stereotype.Service import reactor.core.publisher.Mono +import java.time.Duration + @Data @NoArgsConstructor @@ -32,8 +36,39 @@ class User { var user_name: String? = null var isAccept : String? = null var isAdmin : String? = null + + fun checkValid() : Boolean { + if ( + ((user_id?.length ?: 0) > 5) && + ((user_pw?.length ?: 0) > 9) && + ((user_email?.length ?: 0) > 8) && + user_email?.contains("@") == true && + user_email?.contains(".") == true && + (user_email?.split("@")?.get(0)?.length ?: 0) > 1 && + (user_email?.split("@")?.get(1)?.length ?: 0) > 1 && + (user_email?.split(".")?.get(1)?.length ?: 0) > 1 + ) { + if (user_id.equals("lun_admin") || user_id.equals("lunaticbum")){ + isAdmin = "Y" + } else { + isAccept = "N" + isAdmin = "N" + } + return true + } + return false + } } +@Getter +@RequiredArgsConstructor +enum class Role(key : String, description: String) { + USER("ROLE_USER", "일반사용자"), + ADMIN("ROLE_ADMIN", "일반관리자"); + + private val key: String? = null + private val title: String? = null +} @Repository interface UserRepository : ReactiveMongoRepository { @@ -48,7 +83,7 @@ interface UserService { } @Service -class UserManager : UserService { +class UserManager : UserService , UserDetailsService { @Autowired private lateinit var logService: LogService @@ -70,4 +105,10 @@ class UserManager : UserService { // println("saved user comp") // }) } + + override fun loadUserByUsername(username: String?): UserDetails { + var user = findById(username!!)?.blockOptional(Duration.ofMillis(5000L))?.get() ?: User() + logService.log("username ${username}") + return org.springframework.security.core.userdetails.User.builder().username(user.user_id ?: "").password(user.user_pw).roles(if ("Y".equals(user.isAdmin)) Role.ADMIN.name else {Role.USER.name}).build() + } } \ No newline at end of file diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/service/UserDetailsService.kt b/src/main/kotlin/kr/lunaticbum/back/lun/service/UserDetailsService.kt new file mode 100644 index 0000000..07b63bf --- /dev/null +++ b/src/main/kotlin/kr/lunaticbum/back/lun/service/UserDetailsService.kt @@ -0,0 +1,8 @@ +package kr.lunaticbum.back.lun.service + +import kr.lunaticbum.back.lun.model.User +import kr.lunaticbum.back.lun.model.UserRepository +import lombok.RequiredArgsConstructor +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Service diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 51acd8d..5c76b81 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,10 +9,10 @@ spring.datasource.driver-class-name=org.mariadb.jdbc.Driver #spring.data.mongodb.port=27017 #spring.data.mongodb.database=lun_db #SSL -server.ssl.key-store=classpath:prv.p12 -server.ssl.key-store-type=PKCS12 -server.ssl.key-store-password=VioPup*383 -server.http2.enabled=true +#server.ssl.key-store=classpath:prv.p12 +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store-password=VioPup*383 +#server.http2.enabled=true #spring.main.web-application-type=SERVLET #logging.level.org.springframework.boot.autoconfigure=ERROR #spring.mvc.view.prefix=/templates @@ -28,7 +28,7 @@ spring.thymeleaf.suffix=.html telegram.bot.key=1 telegram.my.id=2 telegram.target.id=3 -weather.api.key=3 +weather.api.key=3 spring.data.mongodb.option.min-connection-per-host=0 spring.data.mongodb.option.max-connection-per-host=100 spring.data.mongodb.option.threads-allowed-to-block-for-connection-multiplier=5 diff --git a/src/main/resources/templates/user/join.html b/src/main/resources/templates/user/join.html index 5996c26..a9a5d17 100644 --- a/src/main/resources/templates/user/join.html +++ b/src/main/resources/templates/user/join.html @@ -94,12 +94,13 @@ // document.getElementById("name").innerText = result.name; // document.getElementById("age").innerText = result.age; } else { + alert(httpRequest.response); alert('Request Error!'); } } }; /* Get 방식으로 name 파라미터와 함께 요청 */ - httpRequest.open('POST', 'joinUser.api', true); + httpRequest.open('POST', 'joinUser.ajax', true); httpRequest.setRequestHeader("Content-Type", "text/plain"); let data = {