diff --git a/Dockerfile b/Dockerfile index f2c9353..442095b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,6 @@ COPY ${JAR_FILE} app.jar EXPOSE 443 #EXPOSE 27012 #EXPOSE 3307 -ENTRYPOINT ["java","-Dtelegram.bot.key=${BOT_KEY}","-Dtelegram.my.id=${TG_MINE}","-Dtelegram.target.id=${TG_TARGET_ID}","-Dweather.api.key=${WEATHER_KEY}","-Dspring.datasource.url=${DATASOURCE_URL}" ,"-Dspring.data.mongodb.uri=${MONGODB_HOST}","-Dspring.data.mongodb.database=${MONGODB_NAME}","-Dspring.datasource.username=${MRA_ADMIN}","-Dspring.datasource.password=${MRA_PW}","-Dresource.handler=${RESOURCE_HANDLER}","-Dresource.location=${RESOURCE_LOCATION}","-Dimage.upload.path=${IMAGE_UPLOAD_PATH}","-Dapi.gg.place=${GAPI_KEY}","-jar","app.jar"] #ENTRYPOINT ["java","-jar","app.jar","-Dspring-boot.run.arguments=--telegram.bot.key=${BOT_KEY}, --telegram.my.id=${TG_MINE}, --telegram.target.id=${TG_TARGET_ID}, --weather.api.key=${WEATHER_KEY}"] +ENTRYPOINT ["java","-Dtelegram.bot.key=${BOT_KEY}","-Dtelegram.my.id=${TG_MINE}","-Dtelegram.target.id=${TG_TARGET_ID}","-Dweather.api.key=${WEATHER_KEY}","-Dspring.datasource.url=${DATASOURCE_URL}" ,"-Dspring.data.mongodb.uri=${MONGODB_HOST}","-Dspring.data.mongodb.database=${MONGODB_NAME}","-Dspring.datasource.username=${MRA_ADMIN}","-Dspring.datasource.password=${MRA_PW}","-Dresource.handler=${RESOURCE_HANDLER}","-Dresource.location=${RESOURCE_LOCATION}","-Dimage.upload.path=${IMAGE_UPLOAD_PATH}","-Dapi.gg.place=${GAPI_KEY}","-jar","app.jar"] #-Dtelegram.bot.key=bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w -Dtelegram.target.id=71476436 -Dtelegram.my.id=71476436 -Dweather.api.key=de574a260b1f474d99955729241909 -Dspring.datasource.url=jdbc:mariadb://mra.sbspace.synology.me -Dspring.data.mongodb.uri=mongodb://lun_admin:VioPup*383@mongo.sbspace.synology.me/?wtimeoutMS=300&connectTimeoutMS=500&socketTimeoutMS=200 -Dspring.data.mongodb.database=lun_db -Dspring.datasource.username=lun_admin -Dspring.datasource.password=VioPup*383 -Dresource.handler=/blog/post/image/** -Dresource.location=file:///imgUpload -Dimage.upload.path=imgUpload diff --git a/build.gradle.kts b/build.gradle.kts index 753ea36..eb03e6b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,6 +50,8 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") + implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6") + implementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect") implementation ("org.jsoup:jsoup:1.18.1") @@ -104,6 +106,7 @@ tasks.withType { tasks.jar { + archiveFileName.set("app.jar") manifest { attributes["Main-Class"] = "kr.lunaticbum.back.lun.LunApplicationKt" } diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/configs/AppConfig.kt b/src/main/kotlin/kr/lunaticbum/back/lun/configs/AppConfig.kt index f1304b7..8e4541b 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/configs/AppConfig.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/configs/AppConfig.kt @@ -4,6 +4,8 @@ import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.CacheControl +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer import java.time.Duration @@ -28,10 +30,13 @@ class AppConfig : WebMvcConfigurer { registry.addResourceHandler(resourceHandler).addResourceLocations(resourceLocation).setCacheControl(cacheControl) } - override fun addInterceptors(registry: InterceptorRegistry) { - registry.addInterceptor(authInterceptor()) - super.addInterceptors(registry) - } + @Bean + fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder() +// override fun addInterceptors(registry: InterceptorRegistry) { +// registry.addInterceptor(authInterceptor()) +// .addPathPatterns("**/*.bs", "**/*.bjx") +// super.addInterceptors(registry) +// } // @Bean diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/configs/BumsInterceptor.kt b/src/main/kotlin/kr/lunaticbum/back/lun/configs/BumsInterceptor.kt index 88421a2..2ddc495 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/configs/BumsInterceptor.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/configs/BumsInterceptor.kt @@ -8,9 +8,9 @@ import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.ApiKeyWordKey import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11 import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey import kr.lunaticbum.back.lun.model.UserManager -import kr.lunaticbum.back.lun.service.JwtService import org.springframework.beans.factory.annotation.Autowired import org.springframework.lang.Nullable +import org.springframework.security.web.authentication.RememberMeServices import org.springframework.stereotype.Component import org.springframework.stereotype.Service import org.springframework.web.servlet.HandlerInterceptor @@ -19,12 +19,8 @@ import org.springframework.web.servlet.ModelAndView @Component class BumsInterceptor : HandlerInterceptor { - @Autowired - lateinit var jwtService : JwtService @Autowired lateinit var globalEvv : GlobalEnvironment - @Autowired - lateinit var userManager: UserManager val WRITE_PERMISSION_KEY = "PERMISSION" @@ -36,9 +32,13 @@ class BumsInterceptor : HandlerInterceptor { // println("==================== BEGIN ====================") // println("Request URL ===> " + request.requestURL) // } + + return super.preHandle(request, response, handler) } +// @Autowired +// lateinit var rememberMeServices: RememberMeServices @Throws(Exception::class) override fun postHandle( @@ -47,68 +47,9 @@ class BumsInterceptor : HandlerInterceptor { handler: Any, @Nullable modelAndView: ModelAndView? ) { - var skippResourcesExtension = arrayListOf(".ajax",".js",".css","/tlg/",".api","error").filter { request.requestURI.contains(it)}.size > 0 - if (!skippResourcesExtension) { - if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter { - it.name.equals( - "access" - ) && it.value.length > 0 - }.size > 0) { - var refreshOk = false; - var accessOk = false; - var access: Cookie? = null - var refresh: Cookie? = null - request.cookies.forEach { - if (it.name.equals("access", true) && jwtService.validateAccessToken(it.value)) { - access = it - accessOk = true - println("==================== accessOk ${accessOk} ======================") - - } - } - request.cookies.forEach { - if (it.name.equals("refresh", true) && jwtService.validateRefreshToken(access?.value, it.value)) { - refresh = it - refreshOk = true - println("==================== refreshOk ${refreshOk} ======================") - } - } - if (refreshOk || accessOk) { - request.getSession(true)?.let { session -> - session.setAttribute(WRITE_PERMISSION_KEY, true) - session.maxInactiveInterval = 60 * 5 - } - } else { - - } - } else if (request.requestURI.contains("logout")) { - request.getSession(true)?.let { session -> - session.invalidate() - session.setAttribute(WRITE_PERMISSION_KEY, false) - } - } - - request.cookies?.forEach { - if (it.name.equals("CLEAR", true)) { - request.getSession(false)?.let { session -> -// session.invalidate() - session.setAttribute(WRITE_PERMISSION_KEY, false) - } - } - } - modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY,"NO") - request.getSession(true)?.let { - (it.getAttribute(WRITE_PERMISSION_KEY) as? Boolean)?.let { permission -> - if (permission) { - modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY,"OK") - modelAndView?.modelMap?.put(EncTypeKey, EncType11) - modelAndView?.modelMap?.put(ApiKeyWordKey,"Def") - } - } - } - println("==================== END ======================") - println("===============================================") - } +// if(remeberMe && authResult != null) { +// rememberMeServices.loginSuccess(httpServletRequest, responce, authResult) +// } super.postHandle(request, response, handler, modelAndView) } diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/configs/GlobalEnvironment.kt b/src/main/kotlin/kr/lunaticbum/back/lun/configs/GlobalEnvironment.kt index 18a060a..e6b97d7 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/configs/GlobalEnvironment.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/configs/GlobalEnvironment.kt @@ -18,19 +18,19 @@ class GlobalEnvironment : EnvironmentAware { fun padding(key : String) = pad.plus(key).plus(pad) } @Value("\${telegram.bot.key}") - var telegramBotKey: String? = "" + lateinit var telegramBotKey: String @Value("\${telegram.my.id}") - var telegramMyId: String? = "" + lateinit var telegramMyId: String @Value("\${telegram.target.id}") - var telegramTargetId: String? = "" + lateinit var telegramTargetId: String @Value("\${weather.api.key}") - var weatherApiKey: String? = "" + lateinit var weatherApiKey: String @Value("\${api.gg.place}") - var gapiKey : String? = "" + lateinit var gapiKey: String // @Value("jwt.access-secret") var ACCESS_SECRET_KEY: String = "l00u00n00a00t00i00c00b00u00m00a00c00sk" @@ -42,6 +42,7 @@ class GlobalEnvironment : EnvironmentAware { var REFRESH_EXPIRATION: Long = 60 * 30 * 1000L override fun setEnvironment(environment: Environment) { + environment.activeProfiles.forEach { println(it) } println ("telegramBotKey $telegramBotKey") println("telegramMyId $telegramMyId") println("telegramMyId $telegramTargetId") diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt b/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt index 078cce0..b1ea90a 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/configs/SecurityConfig.kt @@ -3,6 +3,7 @@ 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.UserManager import kr.lunaticbum.back.lun.utils.LogService import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean @@ -11,6 +12,8 @@ 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.authentication.AuthenticationManager +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder 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 @@ -24,60 +27,87 @@ import org.springframework.web.ErrorResponse @Configuration @EnableWebSecurity -class SecurityConfig { +class SecurityConfig( + private val userManager: UserManager, + private val bCryptPasswordEncoder: BCryptPasswordEncoder +) { @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.csrf { csrf -> + csrf.ignoringRequestMatchers("/user/login.bjx", "/user/joinUser.bjx") // 여기 예외 추가 + }.authorizeHttpRequests { auth -> + auth + .requestMatchers( + "/", "/home", + "/bums/where.bs" , + "/user/login.bs", "/user/signup.bs","/user/login.bjx", + "/css/**", "/js/**", "/images/**", "/webjars/**", "/assets/**").permitAll() + .anyRequest().authenticated() + }.formLogin { form -> + form.loginPage("/user/login.bs") + .defaultSuccessUrl("/", true) + .permitAll() + }.rememberMe { rememberMe -> + rememberMe + .key("BsTs*!12@") // 보통 안전한 키 지정 + .tokenValiditySeconds(60 * 60 * 24 * 7) // 7일간 유효 + .userDetailsService(userManager) // 사용자 정보 서비스 지정 + }.logout { logout -> + logout.logoutUrl("/user/logout.bs").logoutSuccessUrl("/").permitAll() } - } - - http.authorizeHttpRequests { - logService.log(it.toString()) - it.requestMatchers(HttpMethod.POST,"/user/**").permitAll() -// it.requestMatchers(HttpMethod.POST,"/user/**").permitAll() -// 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.requestMatchers("/blog/viewer/**").permitAll() - it.anyRequest().permitAll() - -// .requestMatchers("/", "/login/**").permitAll() - -// .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() } + @Bean + fun authenticationManager(http: HttpSecurity): AuthenticationManager { + val authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java) + authenticationManagerBuilder + .userDetailsService(userManager) + .passwordEncoder(bCryptPasswordEncoder) + return authenticationManagerBuilder.build() // .and() 없이 직접 build() 호출 + } +// @Bean +// fun filterChain(http: HttpSecurity): SecurityFilterChain { +// +// http.csrf { +// it.ignoringRequestMatchers("/user/joinUser.bjx").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("/blog/viewer/**").permitAll() +// it.anyRequest().permitAll() +// } +// 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("아직 못들어와"), diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BlogController.kt b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BlogController.kt index 7de4a07..43a0110 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BlogController.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BlogController.kt @@ -13,7 +13,6 @@ import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.ApiKeyWordKey import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11 import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey import kr.lunaticbum.back.lun.model.* -import kr.lunaticbum.back.lun.service.JwtService import kr.lunaticbum.back.lun.utils.LogService import kr.lunaticbum.back.lun.utils.getFileExtension import net.coobird.thumbnailator.Thumbnails @@ -28,6 +27,8 @@ import org.springframework.core.io.Resource import org.springframework.core.io.UrlResource import org.springframework.http.MediaType import org.springframework.http.ResponseEntity +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.core.userdetails.UserDetails import org.springframework.web.bind.annotation.* import org.springframework.web.multipart.MultipartFile import org.springframework.web.reactive.function.client.WebClient @@ -55,7 +56,7 @@ class BlogController() { @Autowired lateinit var logService: LogService val WRITE_PERMISSION_KEY = "PERMISSION" - @GetMapping("write/{token}","write") + @GetMapping("write/{token}","write.bs") fun writ(@PathVariable token : String? ) : ResultMV{ val vm = ResultMV("content/blog/write") if (token.equals(TEMPTOKEN)) { @@ -67,17 +68,10 @@ class BlogController() { } else { vm.modelMap.put(WRITE_PERMISSION_KEY,"NO") } -// when(System.currentTimeMillis() % 5L) { -// 0L -> vm.modelMap.put(EncTypeKey,"T4") -// 1L -> vm.modelMap.put(EncTypeKey,"T3") -// 2L -> vm.modelMap.put(EncTypeKey,"T2") -// else -> vm.modelMap.put(EncTypeKey,"T0") -// } - return vm } - @PostMapping("post.ajax") + @PostMapping("post.bjx") fun post(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity { logService.log(httpServletRequest.requestURI) logService.log(jsonString) @@ -164,28 +158,27 @@ class BlogController() { return vm } - @Autowired - lateinit var jwtService : JwtService - @GetMapping("modify") + @GetMapping("modify.bs") fun modify(httpServletRequest: HttpServletRequest, @RequestParam("token") token : String?) : ResultMV{ logService.log("incoming modify") val vm = ResultMV("content/blog/modify") - vm.modelMap.put(WRITE_PERMISSION_KEY,"NO") - httpServletRequest.getSession(true)?.let { session -> - (session.getAttribute(WRITE_PERMISSION_KEY) as? Boolean)?.let { - postManageg.find20()?.apply { - forEach { - it.title = URLDecoder.decode(it.title) - val content = URLDecoder.decode(it.content) - it.content = if (content.length > 50) content.substring(0,150) else content - } - vm.modelMap.put("chunkedPosts", this.chunked(3)) + val authentication = SecurityContextHolder.getContext().authentication + val principal = authentication.principal + if (principal is UserDetails) { + val username = principal.username + // 추가 정보 사용 가능 + postManageg.find20()?.apply { + forEach { + it.title = URLDecoder.decode(it.title) + val content = URLDecoder.decode(it.content) + it.content = if (content.length > 50) content.substring(0,150) else content } - vm.modelMap.put(WRITE_PERMISSION_KEY,"OK") - vm.modelMap.put("path","editor/") - vm.modelMap.put("SK",token) + vm.modelMap.put("chunkedPosts", this.chunked(3)) } + vm.modelMap.put(WRITE_PERMISSION_KEY,"OK") + vm.modelMap.put("path","editor/") + vm.modelMap.put("SK",token) } vm.modelMap.put("rowKey","chunkedPosts_") return vm diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BumsPrivate.kt b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BumsPrivate.kt index 4682b5b..7da3ade 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BumsPrivate.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/BumsPrivate.kt @@ -30,7 +30,7 @@ class BumsPrivate { @Autowired lateinit var locationService: LocationLogService - @GetMapping("where") + @GetMapping("where.bs") fun where() : ResultMV { val m = ResultMV("content/private/where") 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 67c7ca3..3ebadf5 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/controllers/UserController.kt @@ -9,7 +9,6 @@ import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11 import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey import kr.lunaticbum.back.lun.configs.JwtRule import kr.lunaticbum.back.lun.model.* -import kr.lunaticbum.back.lun.service.JwtService import kr.lunaticbum.back.lun.utils.JwtUtil import kr.lunaticbum.back.lun.utils.LogService import kr.lunaticbum.back.lun.utils.extractModelData @@ -17,12 +16,18 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.http.ResponseCookie import org.springframework.http.ResponseEntity +import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.core.userdetails.UserDetails import org.springframework.web.bind.annotation.* import org.springframework.web.reactive.function.client.WebClient - +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.web.authentication.RememberMeServices +import org.springframework.security.web.context.HttpSessionSecurityContextRepository import java.io.File import java.util.* +import javax.naming.AuthenticationException @RestController @@ -38,10 +43,8 @@ class UserController { @Autowired lateinit var userManager: UserManager - @Autowired - lateinit var jwtService : JwtService - @GetMapping("join") + @GetMapping("join.bs") fun hello(httpServletRequest: HttpServletRequest): ResultMV { logService.log("onJoin") val vm = ResultMV("content/user/join") @@ -60,7 +63,7 @@ class UserController { return vm } - @GetMapping("login") + @GetMapping("login.bs") fun userLogin(httpServletRequest: HttpServletRequest): ResultMV { logService.log("onJoin") val vm = ResultMV("content/user/login") @@ -69,72 +72,93 @@ class UserController { return vm } +// @GetMapping("logout.bs") +// fun logoutBs(session: HttpSession): ResultMV { +// session.invalidate(); // 세션 날리기 (로그아웃) +// return "redirect:/"; // 홈으로 이동 +// } + + @Autowired + lateinit var authenticationManager: AuthenticationManager + @ResponseBody - @PostMapping("login.ajax") + @PostMapping("login.bjx") fun login(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity { - try { + try { - logService.log(httpServletRequest.requestURI) - logService.log(jsonString) - var lResultCode = 0 - var lResultMsg = "Suscces" - var u : UserDetails? = null - var user : User? = null - var tokenData : TokenData? = null - jsonString.extractModelData { exception, originDataString -> - if (exception == null) { - logService.log(originDataString) - val target = Gson().fromJson(originDataString, User::class.java) ?: User() - user = userManager.findById(target.user_id?.trim() ?: "")?.block() - if (user == null && ((target.user_id?.trim()?.length ?: 0) > 3 == true)) { - user = userManager.findByEmail(target.user_id?.trim() ?: "")?.block() - } - if (user != null) { - if(userManager.isCorrectUser(user!!,target.user_pw!!)){ - tokenData = jwtService.generate(user!!) - } else { - lResultMsg = "is wrong infomation id or passord" - lResultCode = 7100 - } - } else { - lResultMsg = "not founding user[can't find same id,email.. ]" - lResultCode = 7100 - } - } else { - exception.printStackTrace() - lResultMsg = exception.message ?: "unknown exception" - lResultCode = 7999 - } - } - val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).headers { + logService.log(httpServletRequest.requestURI) + logService.log(jsonString) + var lResultCode = 0 + var lResultMsg = "Suscces" + var u : UserDetails? = null + var user : User? = null + var tokenData : TokenData? = null + var remeberMe = false + var authResult : Authentication? = null + jsonString.extractModelData { exception, originDataString -> + if (exception == null) { + logService.log("originDataString >>> $originDataString") + val target = Gson().fromJson(originDataString, User::class.java) ?: User() + try { + val authToken = UsernamePasswordAuthenticationToken(target.user_id, target.user_pw) + authResult = authenticationManager.authenticate(authToken) // 인증 시도 + println("authResult >>>> $authResult") + // 인증 성공 시 SecurityContextHolder에 인증 정보 저장 + SecurityContextHolder.getContext().authentication = authResult - }.body(LoginResult().apply { - this.isOk = lResultCode == 0 - this.resultCode = lResultCode - this.resultMsg = lResultMsg - this.token = setTokenToCookie(JwtRule.ACCESS_PREFIX.value, tokenData?.tokenKey ?: "", globalEvv.ACCESS_EXPIRATION / 1000).toString().replace("access=","") - this.refresh = setTokenToCookie(JwtRule.REFRESH_PREFIX.value, tokenData?.refreshToken ?: "", globalEvv.REFRESH_EXPIRATION / 1000).toString().replace("refresh=","") - }).apply { + // 인증 정보가 담긴 SecurityContext를 세션에 저장 + val session = httpServletRequest.getSession(true) + session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()) + println("authResult >>>> LOGIN OK") + + val principal = authResult?.principal + if (principal is UserDetails) { + val username = principal.username + + val session = httpServletRequest.getSession(true) + session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()) + remeberMe = target.remeberMe ?: false + } else { + lResultMsg = "is wrong infomation id or passord" + lResultCode = 7100 + } + } catch (e: Exception) { + e.printStackTrace() + } + } else { + exception.printStackTrace() + lResultMsg = exception.message ?: "unknown exception" + lResultCode = 7999 + } + } + val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).headers { + + }.body(LoginResult().apply { + this.isOk = lResultCode == 0 + this.resultCode = lResultCode + this.resultMsg = lResultMsg + this.token = setTokenToCookie(JwtRule.ACCESS_PREFIX.value, tokenData?.tokenKey ?: "", globalEvv.ACCESS_EXPIRATION / 1000).toString().replace("access=","") + this.refresh = setTokenToCookie(JwtRule.REFRESH_PREFIX.value, tokenData?.refreshToken ?: "", globalEvv.REFRESH_EXPIRATION / 1000).toString().replace("refresh=","") + }).apply { + + } + + return responce + }catch (e: Exception){ + return ResponseEntity.internalServerError().contentType(MediaType.APPLICATION_JSON).headers { + + }.body(LoginResult().apply { + this.isOk = false + this.resultCode = -999 + this.resultMsg = e.message ?: "unknown exception" + this.token = "" + this.refresh = "" + }).apply { - } - - return responce - }catch (e: Exception){ - return ResponseEntity.internalServerError().contentType(MediaType.APPLICATION_JSON).headers { - - }.body(LoginResult().apply { - this.isOk = false - this.resultCode = -999 - this.resultMsg = e.message ?: "unknown exception" - this.token = "" - this.refresh = "" - }).apply { - - - } - } + } + } } @@ -149,7 +173,7 @@ class UserController { } @ResponseBody - @PostMapping("logout.ajax") + @PostMapping("logout.bjx") fun logout(httpServletRequest: HttpServletRequest) : ResponseEntity { val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(ResponceResult().apply { @@ -158,7 +182,7 @@ class UserController { } @ResponseBody - @PostMapping("joinUser.ajax") + @PostMapping("joinUser.bjx") fun joinUser(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity { logService.log("${httpServletRequest.requestURI}") logService.log(jsonString) @@ -174,9 +198,6 @@ class UserController { }else if (userManager.findById(user!!.user_id!!)?.block() != null) { lResultCode = 7001 lResultMsg = "user insert Fail Reason : already has Same Id" - }else if (userManager.findByEmail(user!!.user_email!!)?.block() != null ) { - lResultCode = 7002 - lResultMsg = "user insert Fail Reason : already has Same Email" } else { u = userManager.save(user).block() } 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 28579f3..746bfc2 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/model/User.kt @@ -39,10 +39,12 @@ class User { @CreatedDate var user_join: Long = 0L - var user_name: String? = null +// var user_name: String? = null var isAccept : String? = null var isAdmin : String? = null + var remeberMe : Boolean? = false + fun checkValid() : Boolean { if ( ((user_id?.length ?: 0) > 5) && @@ -111,8 +113,8 @@ interface UserRepository : ReactiveMongoRepository { @Query("{user_id :?0}") override fun findById(user_id: String): Mono - @Query("{user_email :?0}") - fun findByEmail(user_email: String): Mono +// @Query("{user_email :?0}") +// fun findByEmail(user_email: String): Mono fun save(user: User): Mono @@ -123,23 +125,24 @@ enum class UserRole { } interface UserService { fun findById(id: String): Mono? - fun findByEmail(id: String): Mono? +// fun findByEmail(id: String): Mono? } @Service -class UserManager : UserService , UserDetailsService { +class UserManager( + private val passwordEncoder: PasswordEncoder +) : UserService , UserDetailsService { @Autowired private lateinit var logService: LogService @Autowired private lateinit var userRepository: UserRepository - @Autowired - private lateinit var bCryptPasswordEncoder: PasswordEncoder - override fun findByEmail(id: String): Mono? { - return userRepository.findByEmail(id) - } + +// override fun findByEmail(id: String): Mono? { +// return userRepository.findByEmail(id) +// } override fun findById(id: String): Mono? { return userRepository.findById(id) @@ -149,19 +152,22 @@ class UserManager : UserService , UserDetailsService { fun save(user: User): Mono { println("saved user before ${user}") - user.hashPassword(bCryptPasswordEncoder) + user.hashPassword(passwordEncoder) return userRepository.save(user) } fun isCorrectUser(user: User, password : String) : Boolean { - return user.checkPassword(password,bCryptPasswordEncoder) + return user.checkPassword(password,passwordEncoder) } override fun loadUserByUsername(username: String?): UserDetails { - var user = findById(username!!)?.blockOptional(Duration.ofMillis(5000L))?.get() ?: User() logService.log("username ${username}") - user.hashPassword(bCryptPasswordEncoder) - 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() + var user = findById(username!!)?.blockOptional(Duration.ofMillis(5000L))?.get() ?: User() +// user.hashPassword(passwordEncoder) + 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/JwtService.kt b/src/main/kotlin/kr/lunaticbum/back/lun/service/JwtService.kt index 3735d88..7e0befe 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/service/JwtService.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/service/JwtService.kt @@ -1,185 +1,185 @@ -package kr.lunaticbum.back.lun.service - -import io.jsonwebtoken.Claims -import io.jsonwebtoken.Jws -import io.jsonwebtoken.Jwts -import jakarta.servlet.http.Cookie -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import kr.lunaticbum.back.lun.configs.GlobalEnvironment -import kr.lunaticbum.back.lun.configs.JwtGenerator -import kr.lunaticbum.back.lun.configs.JwtRule -import kr.lunaticbum.back.lun.configs.TokenStatus -import kr.lunaticbum.back.lun.model.* -import kr.lunaticbum.back.lun.utils.BusinessException -import kr.lunaticbum.back.lun.utils.ErrorCode -import kr.lunaticbum.back.lun.utils.JwtUtil -import lombok.extern.slf4j.Slf4j -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.http.HttpHeaders -import org.springframework.http.ResponseCookie -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.core.Authentication -import org.springframework.security.core.token.Token -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional -import java.security.Key -import java.time.Duration -import java.util.* -import java.util.function.Consumer - - -@Service -@Transactional(readOnly = true) -@Slf4j -class JwtService { - - @Autowired - lateinit var globalEvv : GlobalEnvironment - - @Autowired - private lateinit var jwtGenerator: JwtGenerator - - @Autowired - private lateinit var jwtUtil: JwtUtil - - - @Autowired - private lateinit var customUserDetailsService: UserManager - - @Autowired - private lateinit var tokenRepository : TokenDataRepository - -// private val ACCESS_SECRET_KEY: Key = jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY) -// private val REFRESH_SECRET_KEY: Key = jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY) - - fun validateUser(requestUser: User) { - if (requestUser.getRole() === UserRole.NOT_REGISTERED) { - throw BusinessException(ErrorCode.NOT_AUTHENTICATED_USER) - } - } - - @Transactional - fun generate(requestUser: User): TokenData? { - var accessToken = jwtGenerator.generateAccessToken(jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY), globalEvv.ACCESS_EXPIRATION, requestUser) - var refreshToken = jwtGenerator.generateRefreshToken(jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY), globalEvv.REFRESH_EXPIRATION, requestUser) - var token = TokenData(accessToken, refreshToken) - return tokenRepository.save(token).block() - } - - - private fun setTokenToCookie(tokenPrefix: String, token: String, maxAgeSeconds: Long): ResponseCookie { - return ResponseCookie.from(tokenPrefix, token) - .path("/") - .maxAge(maxAgeSeconds) - .httpOnly(true) - .sameSite("None") - .secure(true) - .build() - } - - fun validateAccessToken(token: String?): Boolean { - return jwtUtil.getTokenStatus(token, jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY)) == TokenStatus.AUTHENTICATED - } - - fun validateRefreshToken(token: String?, refreshToken: String?): Boolean { - try { - val isRefreshValid = jwtUtil.getTokenStatus(refreshToken, jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY)) == TokenStatus.AUTHENTICATED - val storedToken: TokenData? = tokenRepository.findBytokenKey(token ?: "").block(Duration.ofSeconds(10)) - val isTokenMatched: Boolean = storedToken?.refreshToken.equals(refreshToken) - return isRefreshValid && isTokenMatched - } catch (e :Exception){ - - } - return false - } - - fun resolveTokenFromCookie(request: HttpServletRequest, tokenPrefix: JwtRule?): String { - val cookies = request.cookies ?: throw BusinessException(ErrorCode.JWT_TOKEN_NOT_FOUND) - return jwtUtil.resolveTokenFromCookie(cookies, tokenPrefix!!) - } - - fun getAuthentication(token: String): Authentication { - val principal: UserDetails = customUserDetailsService.loadUserByUsername(getUserPk(token, jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY))) - return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) - } - - private fun getUserPk(token: String, secretKey: Key): String { - return Jwts.parserBuilder() - .setSigningKey(secretKey) - .build() - .parseClaimsJws(token) - .getBody() - .getSubject() - } - - fun getIdentifierFromRefresh(refreshToken: String?): String { - try { - return Jwts.parserBuilder() - .setSigningKey(jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY)) - .build() - .parseClaimsJws(refreshToken) - .getBody() - .getSubject() - } catch (e: Exception) { - throw BusinessException(ErrorCode.INVALID_JWT) - } - } - - fun logout(token: String, response: HttpServletResponse) { - tokenRepository.deleteBytokenKey(token) - - val accessCookie = jwtUtil.resetToken(JwtRule.ACCESS_PREFIX) - val refreshCookie = jwtUtil.resetToken(JwtRule.REFRESH_PREFIX) - - response.addCookie(accessCookie) - response.addCookie(refreshCookie) - } - fun getUserIdFromToken(token: String?): String? { - try { - return jwtUtil.extractToken(token,jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY))?.body?.get("Identifier") - .toString() - } catch (e: Exception) { - return null - } - } - fun getUserIdFromRefresh(token: String?): String? { - try { - return jwtUtil.extractToken(token,jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY))?.body?.get("Identifier") - .toString() - } catch (e: Exception) { - return null - } - } - - - - fun hasPerrmission(request: HttpServletRequest): Boolean { - var correctUserCheck = -1; - if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter { it.name.equals("access") && it.value.length > 0 }.size > 0) { - var access : Cookie?= null - var refresh : Cookie?= null - request.cookies.forEach { - if (it.name.equals("access", true) && validateAccessToken(it.value)){ - access = it - correctUserCheck += 1 - } - } - request.cookies.forEach { - if (it.name.equals("refresh", true) && validateRefreshToken(access?.value,it.value)){ - refresh = it - correctUserCheck += 1 - } - } - if (correctUserCheck > 0) { - println("Response correctUserCheck ===> ${correctUserCheck}") - } else { - println("Response correctUserCheck ===> ${correctUserCheck}") - } - } else if (request.requestURI.contains("logout")) { - - } - return correctUserCheck > 0 - } -} \ No newline at end of file +//package kr.lunaticbum.back.lun.service +// +//import io.jsonwebtoken.Claims +//import io.jsonwebtoken.Jws +//import io.jsonwebtoken.Jwts +//import jakarta.servlet.http.Cookie +//import jakarta.servlet.http.HttpServletRequest +//import jakarta.servlet.http.HttpServletResponse +//import kr.lunaticbum.back.lun.configs.GlobalEnvironment +//import kr.lunaticbum.back.lun.configs.JwtGenerator +//import kr.lunaticbum.back.lun.configs.JwtRule +//import kr.lunaticbum.back.lun.configs.TokenStatus +//import kr.lunaticbum.back.lun.model.* +//import kr.lunaticbum.back.lun.utils.BusinessException +//import kr.lunaticbum.back.lun.utils.ErrorCode +//import kr.lunaticbum.back.lun.utils.JwtUtil +//import lombok.extern.slf4j.Slf4j +//import org.springframework.beans.factory.annotation.Autowired +//import org.springframework.http.HttpHeaders +//import org.springframework.http.ResponseCookie +//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +//import org.springframework.security.core.Authentication +//import org.springframework.security.core.token.Token +//import org.springframework.security.core.userdetails.UserDetails +//import org.springframework.stereotype.Service +//import org.springframework.transaction.annotation.Transactional +//import java.security.Key +//import java.time.Duration +//import java.util.* +//import java.util.function.Consumer +// +// +//@Service +//@Transactional(readOnly = true) +//@Slf4j +//class JwtService { +// +// @Autowired +// lateinit var globalEvv : GlobalEnvironment +// +// @Autowired +// private lateinit var jwtGenerator: JwtGenerator +// +// @Autowired +// private lateinit var jwtUtil: JwtUtil +// +// +// @Autowired +// private lateinit var customUserDetailsService: UserManager +// +// @Autowired +// private lateinit var tokenRepository : TokenDataRepository +// +//// private val ACCESS_SECRET_KEY: Key = jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY) +//// private val REFRESH_SECRET_KEY: Key = jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY) +// +// fun validateUser(requestUser: User) { +// if (requestUser.getRole() === UserRole.NOT_REGISTERED) { +// throw BusinessException(ErrorCode.NOT_AUTHENTICATED_USER) +// } +// } +// +// @Transactional +// fun generate(requestUser: User): TokenData? { +// var accessToken = jwtGenerator.generateAccessToken(jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY), globalEvv.ACCESS_EXPIRATION, requestUser) +// var refreshToken = jwtGenerator.generateRefreshToken(jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY), globalEvv.REFRESH_EXPIRATION, requestUser) +// var token = TokenData(accessToken, refreshToken) +// return tokenRepository.save(token).block() +// } +// +// +// private fun setTokenToCookie(tokenPrefix: String, token: String, maxAgeSeconds: Long): ResponseCookie { +// return ResponseCookie.from(tokenPrefix, token) +// .path("/") +// .maxAge(maxAgeSeconds) +// .httpOnly(true) +// .sameSite("None") +// .secure(true) +// .build() +// } +// +// fun validateAccessToken(token: String?): Boolean { +// return jwtUtil.getTokenStatus(token, jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY)) == TokenStatus.AUTHENTICATED +// } +// +// fun validateRefreshToken(token: String?, refreshToken: String?): Boolean { +// try { +// val isRefreshValid = jwtUtil.getTokenStatus(refreshToken, jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY)) == TokenStatus.AUTHENTICATED +// val storedToken: TokenData? = tokenRepository.findBytokenKey(token ?: "").block(Duration.ofSeconds(10)) +// val isTokenMatched: Boolean = storedToken?.refreshToken.equals(refreshToken) +// return isRefreshValid && isTokenMatched +// } catch (e :Exception){ +// +// } +// return false +// } +// +// fun resolveTokenFromCookie(request: HttpServletRequest, tokenPrefix: JwtRule?): String { +// val cookies = request.cookies ?: throw BusinessException(ErrorCode.JWT_TOKEN_NOT_FOUND) +// return jwtUtil.resolveTokenFromCookie(cookies, tokenPrefix!!) +// } +// +// fun getAuthentication(token: String): Authentication { +// val principal: UserDetails = customUserDetailsService.loadUserByUsername(getUserPk(token, jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY))) +// return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) +// } +// +// private fun getUserPk(token: String, secretKey: Key): String { +// return Jwts.parserBuilder() +// .setSigningKey(secretKey) +// .build() +// .parseClaimsJws(token) +// .getBody() +// .getSubject() +// } +// +// fun getIdentifierFromRefresh(refreshToken: String?): String { +// try { +// return Jwts.parserBuilder() +// .setSigningKey(jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY)) +// .build() +// .parseClaimsJws(refreshToken) +// .getBody() +// .getSubject() +// } catch (e: Exception) { +// throw BusinessException(ErrorCode.INVALID_JWT) +// } +// } +// +// fun logout(token: String, response: HttpServletResponse) { +// tokenRepository.deleteBytokenKey(token) +// +// val accessCookie = jwtUtil.resetToken(JwtRule.ACCESS_PREFIX) +// val refreshCookie = jwtUtil.resetToken(JwtRule.REFRESH_PREFIX) +// +// response.addCookie(accessCookie) +// response.addCookie(refreshCookie) +// } +// fun getUserIdFromToken(token: String?): String? { +// try { +// return jwtUtil.extractToken(token,jwtUtil.getSigningKey(globalEvv.ACCESS_SECRET_KEY))?.body?.get("Identifier") +// .toString() +// } catch (e: Exception) { +// return null +// } +// } +// fun getUserIdFromRefresh(token: String?): String? { +// try { +// return jwtUtil.extractToken(token,jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY))?.body?.get("Identifier") +// .toString() +// } catch (e: Exception) { +// return null +// } +// } +// +// +// +// fun hasPerrmission(request: HttpServletRequest): Boolean { +// var correctUserCheck = -1; +// if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter { it.name.equals("access") && it.value.length > 0 }.size > 0) { +// var access : Cookie?= null +// var refresh : Cookie?= null +// request.cookies.forEach { +// if (it.name.equals("access", true) && validateAccessToken(it.value)){ +// access = it +// correctUserCheck += 1 +// } +// } +// request.cookies.forEach { +// if (it.name.equals("refresh", true) && validateRefreshToken(access?.value,it.value)){ +// refresh = it +// correctUserCheck += 1 +// } +// } +// if (correctUserCheck > 0) { +// println("Response correctUserCheck ===> ${correctUserCheck}") +// } else { +// println("Response correctUserCheck ===> ${correctUserCheck}") +// } +// } else if (request.requestURI.contains("logout")) { +// +// } +// return correctUserCheck > 0 +// } +//} \ No newline at end of file diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/utils/StringUtils.kt b/src/main/kotlin/kr/lunaticbum/back/lun/utils/StringUtils.kt index b7d2e8a..c6fe141 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/utils/StringUtils.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/utils/StringUtils.kt @@ -65,6 +65,7 @@ fun String.extractModelData(calback : (Exception?,String)->Unit) { Gson().fromJson(resultString, RequestModel::class.java).let { model -> model.data?.let { jsonString -> try { + println("RequestModel ${jsonString}") calback.invoke(null,model.extractData()) } catch (e: Exception) { calback.invoke(ExtractDataRequestModelException("Exception on extractData with ${Gson().toJson(model)}", e.cause), jsonString) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 768e701..de7f7ca 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -86,6 +86,8 @@ spring.ai.vectorstore.qdrant.collection-name=blama_vectors spring.ai.ollama.embedding.enabled=true - +resource.handler=. +resource.location=. +server.forward-headers-strategy=framework #>>>>>>> ab915d0a416c69708f1df1ad76d7a14c779c1f59 diff --git a/src/main/resources/static/css/common.css b/src/main/resources/static/css/common.css index b024ccf..a17557d 100644 --- a/src/main/resources/static/css/common.css +++ b/src/main/resources/static/css/common.css @@ -168,3 +168,31 @@ footer { min-height: 5vh; position: relative; } + +#rememberMe { + width: 20px; + height: 20px; + background-color: lightblue; /* 체크박스 배경색 */ + border: 2px solid blue; /* 테두리 색 */ + appearance: none; /* 기본 OS 스타일 제거 */ + -webkit-appearance: none; + -moz-appearance: none; + cursor: pointer; + position: relative; +} + +#rememberMe:checked { + background-color: blue; +} + +#rememberMe:checked::after { + content: ""; + position: absolute; + top: 3px; + left: 7px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} \ No newline at end of file diff --git a/src/main/resources/static/js/blog.js b/src/main/resources/static/js/blog.js index f366fff..a8f6eae 100644 --- a/src/main/resources/static/js/blog.js +++ b/src/main/resources/static/js/blog.js @@ -31,7 +31,7 @@ function onclickWrite(type, keyword, html) { baseData.firstPostLat = encodeURIComponent(currentLat) baseData.firstPostLon = encodeURIComponent(currentLon) } - let uploadUrl = getMainPath() + "/blog/post.ajax"; + let uploadUrl = getMainPath() + "/blog/post.bjx"; if(confirm(JSON.stringify(baseData) + "\n해당 내용으로\n유저 등록 하실??")) { post(uploadUrl,type,JSON.stringify(baseData),keyword, function (resultData) { alert(resultData) diff --git a/src/main/resources/static/js/common.js b/src/main/resources/static/js/common.js index d6c639f..926e9ec 100644 --- a/src/main/resources/static/js/common.js +++ b/src/main/resources/static/js/common.js @@ -147,7 +147,7 @@ function postLogin(target,type, data, key,callBackResult) { } } - + httpRequest.withCredentials = true httpRequest.open('POST', target, true); httpRequest.setRequestHeader("Content-Type", "text/plain"); var odd = [] @@ -172,15 +172,15 @@ function mainPath() { } function gotoWrite() { - document.location.replace(getMainPath()+"/blog/write") + document.location.replace(getMainPath()+"/blog/write.bs") } function gotoModify() { - document.location.replace(getMainPath()+"/blog/modify") + document.location.replace(getMainPath()+"/blog/modify.bs") } function gotoWhere() { - document.location.replace(getMainPath()+"/bums/where") + document.location.replace(getMainPath()+"/bums/where.bs") } function logout() { @@ -191,21 +191,35 @@ function logout() { console.log(document.cookie["JSESSIONID"]) document.cookie = "JSESSIONID=; expires=Thu, 01 Jan 1970 00:00:01 GMT;" document.cookie = "CLEAR="+Date.now()+""; - let logOutUrl = getMainPath() + "/user/logout.ajax"; - post(logOutUrl,"","","", function (resultData) { - alert("로그아웃 됨요~! 빠염~!") - document.location.replace(document.location) - }) + let logOutUrl = getMainPath() + "/user/logout.bs"; + alert("로그아웃 됨요~! 빠염~!") + + // 동적으로 form 생성하여 POST 요청 전송 + const form = document.createElement('form'); + form.method = 'POST'; + form.action = getMainPath() + '/user/logout.bs'; + + // CSRF 토큰을 meta태그 등에서 얻어서 삽입 (예: ) + const csrfToken = document.querySelector('meta[name="_csrf"]').getAttribute('content'); + const csrfParam = document.querySelector('meta[name="_csrf_parameter"]').getAttribute('content'); + const csrfInput = document.createElement('input'); + csrfInput.type = 'hidden'; + csrfInput.name = csrfParam; // 예: "_csrf" + csrfInput.value = csrfToken; + form.appendChild(csrfInput); + + document.body.appendChild(form); + form.submit(); } function gotoLogin() { console.log(`location.port >> ${location.port}`) - location.href = getMainPath()+"/login" + location.href = getMainPath()+"/login.bs" } function gotoJoin() { - document.location.replace(getMainPath() + "/user/join") + document.location.replace(getMainPath() + "/user/join.bs") } function goToView(path,id) { @@ -218,7 +232,7 @@ function onclickLogin(type, keyword) { 'user_id': user_id.value, 'user_pw': user_pw.value, } - postLogin(getMainPath()+"/user/login.ajax",type,JSON.stringify(data),keyword, function (data) { + postLogin(getMainPath()+"/user/login.bjx",type,JSON.stringify(data),keyword, function (data) { if (data.isOk) { document.cookie = "access=" + data.token.split(";")[0]+";" @@ -229,7 +243,7 @@ function onclickLogin(type, keyword) { } else { if (data.resultCode === 7100) { if(confirm(`너 누구임 정보 없는데?!\n${data.resultMsg}[${data.resultCode}]\n가입 할래!?`)){ - document.location.replace(getMainPath() + "/user/join") + document.location.replace(getMainPath() + "/user/join.bs") } } else { alert(`너 누구임?!\n${data.resultMsg}[${data.resultCode}]`) @@ -320,11 +334,13 @@ function submitLoginForm() { // const password = document.getElementById('loginPassword').value; let user_id = document.getElementById('loginId') let user_pw = document.getElementById('loginPassword') + let rememberMe = document.getElementById('rememberMe') let data = { 'user_id': user_id.value, 'user_pw': user_pw.value, + 'rememberMe' : rememberMe.value, } - postLogin(getMainPath()+"/user/login.ajax",user_pw.data,JSON.stringify(data),user_pw.data, function (data) { + postLogin(getMainPath()+"/user/login.bjx",user_pw.data,JSON.stringify(data),user_pw.data, function (data) { closePopup() if (data.isOk) { document.cookie = "access=" + data.token.split(";")[0]+";" diff --git a/src/main/resources/static/js/user.js b/src/main/resources/static/js/user.js index a207545..ef4e3c8 100644 --- a/src/main/resources/static/js/user.js +++ b/src/main/resources/static/js/user.js @@ -62,7 +62,7 @@ function onclickJoin(type, keyword) { } if (user_pw.value === user_pw_check.value) { if(confirm(JSON.stringify(data) + "\n해당 내용으로\n유저 등록 하실??")) { - post("joinUser.ajax",type,JSON.stringify(data),keyword, function (resultData) { + post("joinUser.bjx",type,JSON.stringify(data),keyword, function (resultData) { alert(resultData) }) } else { diff --git a/src/main/resources/templates/content/blog/editor.html b/src/main/resources/templates/content/blog/editor.html index 5ff7f4c..cb0a4f7 100644 --- a/src/main/resources/templates/content/blog/editor.html +++ b/src/main/resources/templates/content/blog/editor.html @@ -2,6 +2,8 @@ @@ -86,10 +88,10 @@
- +

권한이 없는 뎁쇼?!

- +
diff --git a/src/main/resources/templates/content/blog/modify.html b/src/main/resources/templates/content/blog/modify.html index 4a7e42c..bc7dc3a 100644 --- a/src/main/resources/templates/content/blog/modify.html +++ b/src/main/resources/templates/content/blog/modify.html @@ -2,6 +2,7 @@ @@ -33,10 +34,10 @@
- +

권한이 없는 뎁쇼?!

- +
diff --git a/src/main/resources/templates/content/blog/posts.html b/src/main/resources/templates/content/blog/posts.html index f15d404..3c52d4a 100644 --- a/src/main/resources/templates/content/blog/posts.html +++ b/src/main/resources/templates/content/blog/posts.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/blog/viewer.html b/src/main/resources/templates/content/blog/viewer.html index e5b1faf..1122f8f 100644 --- a/src/main/resources/templates/content/blog/viewer.html +++ b/src/main/resources/templates/content/blog/viewer.html @@ -2,6 +2,7 @@ @@ -38,13 +39,13 @@
-
+

A gigantic heading you can use for whatever

-
+

A gigantic heading you can use for whatever

diff --git a/src/main/resources/templates/content/blog/write.html b/src/main/resources/templates/content/blog/write.html index b721185..cdebbf7 100644 --- a/src/main/resources/templates/content/blog/write.html +++ b/src/main/resources/templates/content/blog/write.html @@ -2,6 +2,7 @@ @@ -100,10 +101,10 @@
- +

권한이 없는 뎁쇼?!

- +
diff --git a/src/main/resources/templates/content/home.html b/src/main/resources/templates/content/home.html index b45bde1..cbe6043 100644 --- a/src/main/resources/templates/content/home.html +++ b/src/main/resources/templates/content/home.html @@ -2,6 +2,7 @@ @@ -10,7 +11,7 @@ diff --git a/src/main/resources/templates/content/licenses.html b/src/main/resources/templates/content/licenses.html index c1702f2..e88bcf8 100644 --- a/src/main/resources/templates/content/licenses.html +++ b/src/main/resources/templates/content/licenses.html @@ -2,6 +2,8 @@ diff --git a/src/main/resources/templates/content/no-sidebar.html b/src/main/resources/templates/content/no-sidebar.html index 87d0285..d65826b 100644 --- a/src/main/resources/templates/content/no-sidebar.html +++ b/src/main/resources/templates/content/no-sidebar.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/private/where.html b/src/main/resources/templates/content/private/where.html index bd18b40..1e0ced1 100644 --- a/src/main/resources/templates/content/private/where.html +++ b/src/main/resources/templates/content/private/where.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/right-sidebar.html b/src/main/resources/templates/content/right-sidebar.html index a56da74..45e9d43 100644 --- a/src/main/resources/templates/content/right-sidebar.html +++ b/src/main/resources/templates/content/right-sidebar.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/two-sidebar.html b/src/main/resources/templates/content/two-sidebar.html index a413978..7fb82be 100644 --- a/src/main/resources/templates/content/two-sidebar.html +++ b/src/main/resources/templates/content/two-sidebar.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/user/join.html b/src/main/resources/templates/content/user/join.html index 01eb4ff..8a5fba5 100644 --- a/src/main/resources/templates/content/user/join.html +++ b/src/main/resources/templates/content/user/join.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/content/user/login.html b/src/main/resources/templates/content/user/login.html index 5aee4e2..01c2507 100644 --- a/src/main/resources/templates/content/user/login.html +++ b/src/main/resources/templates/content/user/login.html @@ -2,6 +2,7 @@ diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html index d327d35..c9e6264 100644 --- a/src/main/resources/templates/fragments/header.html +++ b/src/main/resources/templates/fragments/header.html @@ -1,39 +1,54 @@ - +