diff --git a/README.md b/README.md index e09c953..9b0bda0 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,175 @@ # Orury! +![orury_mockup](https://github.com/Kernel360/E2E1-Orury/assets/44130863/41f0692c-2c24-4709-9f05-aa05827e66be) -당신만의 클라이밍 커뮤니티, 오루리 +
+당신만의 클라이밍 커뮤니티, 오루리!
+내 클라이밍 라이프를 다른 클라이머들과 공유하고, 즐기세요! +
## 멤버 -|Backend| Backend |Backend|Backend| -|:---:|:-----------------------------------------------------------------------------------------------------------------------------:|:---:|:---:| -|| ||| -|[형준](https://github.com/kkkapuq)| [찬욱](https://github.com/mooncw) |[종민](https://github.com/ShineCorine)|[무룡](https://github.com/aqrms)| +| Backend | Backend | Backend | Backend | +|:-----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------:| +| | | | | +| [형준](https://github.com/kkkapuq) | [찬욱](https://github.com/mooncw) | [종민](https://github.com/ShineCorine) | [무룡](https://github.com/aqrms) | +| 팀원들이 본
**형준**은 | 팀원들이 본
**찬욱**은 | 팀원들이 본
**종민**은 | 팀원들이 본
**무룡**은 | +| 중심을 잡아줘요
리더쉽이 강해요
솔선수범한 리더 | 다재다능 행동대장
뭐든지 꼼꼼해요
팀의 해결사 | 부딪히고 보는 진격의 개발자
꾸준하게 성장해요
실력이 쑥쑥자라요 | 끝까지 가면 내가이겨
어려운 일도 파고들어요
책임감이 강해요 | ## 기술 스택 - + ## 서비스 흐름도 -![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/ef0c31d3-623a-4ef8-b9a8-2a8fe0e5706b) +![서비스 흐름도](https://github.com/Kernel360/E2E1-Orury/assets/44130863/20cd677f-370a-4312-a271-73a25436069d) ## CI/CD -![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/23132200-f87c-4137-ad4b-6227a6174caa) +![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/d928aeb7-02e3-4909-96da-1bf31734ef4f) + +## 시스템 아키텍처 +![system_architecture](https://github.com/Kernel360/E2E1-Orury/assets/44130863/22def7c2-e141-4592-a03d-3858e362dcc1) + +## ERD +![ERD](https://github.com/Kernel360/E2E1-Orury/assets/44130863/af21f3c1-4bd2-4703-a765-5a1a3534e3d7) + +## 프로젝트 구조도 +> 📦orury +┣ 📂batch +┃ ┣ 📂job +┃ ┃ ┗ 📜DeleteExpiredTokenJobConfig.java +┃ ┗ 📂scheduler +┃ ┃ ┗ 📜BatchScheduler.java +┣ 📂config +┃ ┣ 📂jwt +┃ ┃ ┣ 📜CustomAuthenticationFailureHandler.java +┃ ┃ ┣ 📜JwtAccessDeniedHandler.java +┃ ┃ ┣ 📜JwtAuthenticationEntryPoint.java +┃ ┃ ┣ 📜JwtFilter.java +┃ ┃ ┣ 📜JwtSecurityConfig.java +┃ ┃ ┗ 📜TokenProvider.java +┃ ┣ 📜CorsConfig.java +┃ ┣ 📜JasyptConfig.java +┃ ┣ 📜SecurityConfig.java +┃ ┗ 📜SwaggerConfig.java +┣ 📂domain +┃ ┣ 📂admin +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┣ 📜AdminBoardController.java +┃ ┃ ┃ ┣ 📜AdminCommentController.java +┃ ┃ ┃ ┣ 📜AdminPostController.java +┃ ┃ ┃ ┗ 📜AdminUserController.java +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┣ 📜AdminCommentService.java +┃ ┃ ┃ ┣ 📜AdminPostService.java +┃ ┃ ┃ ┗ 📜AdminUserService.java +┃ ┣ 📂board +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┗ 📜BoardController.java +┃ ┃ ┣ 📂db +┃ ┃ ┃ ┣ 📜BoardEntity.java +┃ ┃ ┃ ┗ 📜BoardRepository.java +┃ ┃ ┣ 📂model +┃ ┃ ┃ ┣ 📜BoardDto.java +┃ ┃ ┃ ┗ 📜BoardRequest.java +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┣ 📜BoardConverter.java +┃ ┃ ┃ ┗ 📜BoardService.java +┃ ┣ 📂comment +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┗ 📜CommentController.java +┃ ┃ ┣ 📂db +┃ ┃ ┃ ┣ 📜CommentEntity.java +┃ ┃ ┃ ┣ 📜CommentLikeEntity.java +┃ ┃ ┃ ┣ 📜CommentLikePK.java +┃ ┃ ┃ ┣ 📜CommentLikeRepository.java +┃ ┃ ┃ ┗ 📜CommentRepository.java +┃ ┃ ┣ 📂model +┃ ┃ ┃ ┣ 📜CommentDto.java +┃ ┃ ┃ ┣ 📜CommentLikeDto.java +┃ ┃ ┃ ┣ 📜CommentLikeRequest.java +┃ ┃ ┃ ┗ 📜CommentRequest.java +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┣ 📜CommentConverter.java +┃ ┃ ┃ ┗ 📜CommentService.java +┃ ┣ 📂config +┃ ┣ 📂notification +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┗ 📜NotifyController.java +┃ ┃ ┣ 📂db +┃ ┃ ┃ ┗ 📜EmitterRepository.java +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┗ 📜NotifyService.java +┃ ┣ 📂post +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┗ 📜PostController.java +┃ ┃ ┣ 📂db +┃ ┃ ┃ ┣ 📜PostEntity.java +┃ ┃ ┃ ┣ 📜PostLikeEntity.java +┃ ┃ ┃ ┣ 📜PostLikePK.java +┃ ┃ ┃ ┣ 📜PostLikeRepository.java +┃ ┃ ┃ ┗ 📜PostRepository.java +┃ ┃ ┣ 📂model +┃ ┃ ┃ ┣ 📜PostDto.java +┃ ┃ ┃ ┣ 📜PostLikeDto.java +┃ ┃ ┃ ┣ 📜PostLikeRequest.java +┃ ┃ ┃ ┗ 📜PostRequest.java +┃ ┃ ┣ 📂repository +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┣ 📜PostConverter.java +┃ ┃ ┃ ┗ 📜PostService.java +┃ ┗ 📂user +┃ ┃ ┣ 📂controller +┃ ┃ ┃ ┣ 📜AuthController.java +┃ ┃ ┃ ┗ 📜UserController.java +┃ ┃ ┣ 📂db +┃ ┃ ┃ ┣ 📜AuthorityEntity.java +┃ ┃ ┃ ┣ 📜AuthorityRepository.java +┃ ┃ ┃ ┣ 📜RefreshTokenEntity.java +┃ ┃ ┃ ┣ 📜RefreshTokenRepository.java +┃ ┃ ┃ ┣ 📜UserEntity.java +┃ ┃ ┃ ┗ 📜UserRepository.java +┃ ┃ ┣ 📂model +┃ ┃ ┃ ┣ 📜AuthorityDto.java +┃ ┃ ┃ ┣ 📜LoginDto.java +┃ ┃ ┃ ┣ 📜TokenDto.java +┃ ┃ ┃ ┣ 📜UserDto.java +┃ ┃ ┃ ┗ 📜UserResponseDto.java +┃ ┃ ┗ 📂service +┃ ┃ ┃ ┣ 📜CustomUserDetailsService.java +┃ ┃ ┃ ┗ 📜UserService.java +┣ 📂global +┃ ┣ 📂common +┃ ┃ ┣ 📜Api.java +┃ ┃ ┣ 📜ApiResponse.java +┃ ┃ ┣ 📜ApiStatus.java +┃ ┃ ┣ 📜BaseEntity.java +┃ ┃ ┣ 📜Listener.java +┃ ┃ ┣ 📜Pagination.java +┃ ┃ ┗ 📜SecurityUtil.java +┃ ┣ 📂config +┃ ┃ ┗ 📜JpaConfig.java +┃ ┣ 📂constants +┃ ┃ ┗ 📜Constant.java +┃ ┣ 📂controller +┃ ┣ 📂error +┃ ┃ ┣ 📂code +┃ ┃ ┃ ┣ 📜AuthorizationErrorCode.java +┃ ┃ ┃ ┣ 📜BoardErrorCode.java +┃ ┃ ┃ ┣ 📜CertificationErrorCode.java +┃ ┃ ┃ ┣ 📜CommentErrorCode.java +┃ ┃ ┃ ┣ 📜ErrorCode.java +┃ ┃ ┃ ┣ 📜PostErrorCode.java +┃ ┃ ┃ ┣ 📜ServerErrorCode.java +┃ ┃ ┃ ┗ 📜UserErrorCode.java +┃ ┃ ┣ 📂dto +┃ ┃ ┃ ┗ 📜ErrorResponse.java +┃ ┃ ┣ 📂exception +┃ ┃ ┃ ┗ 📜BusinessException.java +┃ ┃ ┗ 📜GlobalExceptionHandler.java +┃ ┗ 📂message +┃ ┃ ┣ 📂info +┃ ┃ ┃ ┗ 📜InfoMessages.java +┃ ┃ ┣ 📂success +┃ ┃ ┗ 📂validation +┗ 📜OruryApplication.java ## 사용법 ### 1. apk를 다운받아서 사용하는 경우 diff --git a/backend/orury/.gitignore b/backend/orury/.gitignore index d99209a..863e9a4 100644 --- a/backend/orury/.gitignore +++ b/backend/orury/.gitignore @@ -6,6 +6,7 @@ build/ !**/src/test/**/build/ LOCAL_LOG_URL_IS_UNDEFINED .DS_Store +AWS_LOG_URL_IS_UNDEFINED/ ### STS ### .apt_generated diff --git a/backend/orury/build.gradle b/backend/orury/build.gradle index 0689877..70fff87 100644 --- a/backend/orury/build.gradle +++ b/backend/orury/build.gradle @@ -47,6 +47,9 @@ dependencies { runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.7.0' + + implementation 'org.flywaydb:flyway-core' + implementation 'org.flywaydb:flyway-mysql' } tasks.named('test') { diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/SecurityConfig.java b/backend/orury/src/main/java/com/kernel360/orury/config/SecurityConfig.java index 62671b3..1031152 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/config/SecurityConfig.java +++ b/backend/orury/src/main/java/com/kernel360/orury/config/SecurityConfig.java @@ -1,17 +1,23 @@ package com.kernel360.orury.config; import com.kernel360.orury.config.jwt.*; +import com.kernel360.orury.config.jwt.admin.AdminJwtAuthenticationEntryPoint; +import com.kernel360.orury.config.jwt.admin.AdminJwtFilter; +import com.kernel360.orury.domain.user.db.UserRepository; +import com.kernel360.orury.domain.user.service.CustomUserDetailsService; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.filter.CorsFilter; @@ -35,20 +41,77 @@ public class SecurityConfig { "/api/notify/**" // sse 테스트를 위해 임시로 ); private final TokenProvider tokenProvider; + private final UserRepository userRepository; private final CorsFilter corsFilter; private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final AdminJwtAuthenticationEntryPoint adminJwtAuthenticationEntryPoint; private final JwtAccessDeniedHandler jwtAccessDeniedHandler; - private CustomAuthenticationFailureHandler failureHandler; + private final CustomUserDetailsService customUserDetailsService; + @Value("${jwt.cookie-name}") + private String cookieName; + @Value("${jwt.refresh-cookie-name}") + private String cookieRefreshName; + @Value("${jwt.access-validity}") + private String accessCookieMaxAge; + @Value("${jwt.refresh-validity}") + private String refreshCookieMaxAge; @Bean - public PasswordEncoder passwordEncoder() { + public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public AuthenticationManager authenticationManager( + HttpSecurity http, + BCryptPasswordEncoder passwordEncoder + ) throws Exception { + return http.getSharedObject(AuthenticationManagerBuilder.class) + .userDetailsService(customUserDetailsService) + .passwordEncoder(passwordEncoder) + .and() + .build(); + } + + @Bean + @Order(1) + public SecurityFilterChain adminFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws + Exception { http - // token을 사용하는 방식이기 때문에 csrf를 disable합니다. + .requestMatchers(requestMatchers -> requestMatchers + .antMatchers("/admin/**") // /api로 시작하는 요청을 처리 + ) + .csrf(csrf -> csrf.disable()) + + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling(exceptionHandling -> exceptionHandling + .accessDeniedHandler(jwtAccessDeniedHandler) + .authenticationEntryPoint(adminJwtAuthenticationEntryPoint) + ) + + .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests + .mvcMatchers(SWAGGER.toArray(new String[0])).permitAll() + .antMatchers("/admin/login").permitAll() + .anyRequest().authenticated() + ) + + // 세션을 사용하지 않기 때문에 STATELESS로 설정 + .sessionManagement(sessionManagement -> + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) + // JWT필터 적용 + .addFilterBefore(new AdminJwtFilter(tokenProvider, cookieName, cookieRefreshName, accessCookieMaxAge, + refreshCookieMaxAge), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + @Order(2) + public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception { + http + .requestMatchers(requestMatchers -> requestMatchers + .antMatchers("/api/**") // /api로 시작하는 요청을 처리 + ) .csrf(csrf -> csrf.disable()) .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/CustomAuthenticationFailureHandler.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/CustomAuthenticationFailureHandler.java index 45213fe..3d6342f 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/CustomAuthenticationFailureHandler.java +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/CustomAuthenticationFailureHandler.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.kernel360.orury.global.common.ApiResponse; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.CertificationErrorCode; import org.springframework.http.HttpStatus; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; @@ -20,7 +20,7 @@ public void onAuthenticationFailure(HttpServletRequest request, HttpServletRespo // 여기에 원하는 JSON 응답을 작성합니다. // 예시로는 ApiResponse를 사용했습니다. - ApiResponse apiResponse = ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, ErrorMessages.EXPIRED_JWT.getMessage()); + ApiResponse apiResponse = ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, CertificationErrorCode.EXPIRED_ACCESS_JWT.getMessage()); new ObjectMapper().writeValue(response.getWriter(), apiResponse); } } \ No newline at end of file diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtAuthenticationEntryPoint.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtAuthenticationEntryPoint.java index 5c43cb4..e0baa9b 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtAuthenticationEntryPoint.java +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtAuthenticationEntryPoint.java @@ -24,7 +24,15 @@ public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException ) { - resolver.resolveException(request, response, null, (Exception) request.getAttribute("exception")); + // JwtFilter에서 처리한 밣생한 예외를 받는 부분 + if(request.getAttribute("exception") != null) { + resolver.resolveException(request, response, null, (Exception) request.getAttribute("exception")); + } + + // jwt token에서 정의한 에러 외 filter에서 발생한 예외를 global handler로 보냄 + else { + resolver.resolveException(request, response, null, authException); + } // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 // response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtFilter.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtFilter.java index 8b1d21e..3dc9e4b 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtFilter.java +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/JwtFilter.java @@ -3,26 +3,23 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.exception.RefreshExpiredJwtException; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.CertificationErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.security.SignatureException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StringUtils; -import org.springframework.web.filter.GenericFilterBean; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; - import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import java.io.IOException; public class JwtFilter extends OncePerRequestFilter { @@ -64,58 +61,39 @@ public void doFilterInternal(HttpServletRequest servletRequest, HttpServletRespo SecurityContextHolder.getContext().setAuthentication(authentication); logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), servletRequest.getRequestURI()); }catch(ExpiredJwtException e){ - RefreshExpiredJwtException refreshExpiredJwtException = new RefreshExpiredJwtException("Refresh Expired Jwt Exception"); + BusinessException refreshExpiredJwtException = new BusinessException(CertificationErrorCode.EXPIRED_REFRESH_JWT); servletRequest.setAttribute("exception", refreshExpiredJwtException); + }catch(SignatureException e) { + BusinessException signatureException = new BusinessException(CertificationErrorCode.ILLEGAL_ARGUMENT_JWT); + servletRequest.setAttribute("exception", signatureException); + }catch (MalformedJwtException e){ + BusinessException newException = new BusinessException(CertificationErrorCode.MALFORMED_JWT); + servletRequest.setAttribute("exception", newException); }catch(Exception e){ servletRequest.setAttribute("exception", e); } -// } catch (ExpiredJwtException e) { -// // Create an ObjectMapper -// ObjectMapper objectMapper = new ObjectMapper(); -// // Create a JSON object -// JsonNode errorJson = objectMapper.createObjectNode() -// .put("error", ErrorMessages.EXPIRED_REFRESH_JWT.getMessage()) -// .put("errorCode", 402); -// // Convert JSON object to string -// tempResponse(objectMapper, errorJson, servletResponse); -// return; -// } }else { try { tokenProvider.validateToken(accessToken); Authentication authentication = tokenProvider.getAuthentication(accessToken); SecurityContextHolder.getContext().setAuthentication(authentication); logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), servletRequest.getRequestURI()); + }catch(ExpiredJwtException e) { + BusinessException accessExpiredJwtException = new BusinessException(CertificationErrorCode.EXPIRED_ACCESS_JWT); + servletRequest.setAttribute("exception", accessExpiredJwtException); + }catch(SignatureException e) { + BusinessException signatureException = new BusinessException(CertificationErrorCode.ILLEGAL_ARGUMENT_JWT); + servletRequest.setAttribute("exception", signatureException); + }catch (MalformedJwtException e){ + BusinessException newException = new BusinessException(CertificationErrorCode.MALFORMED_JWT); + servletRequest.setAttribute("exception", newException); }catch(Exception e){ servletRequest.setAttribute("exception", e); } -// } catch (Exception e) { -// // Create an ObjectMapper -// ObjectMapper objectMapper = new ObjectMapper(); -// // Create a JSON object -// JsonNode errorJson = objectMapper.createObjectNode() -// .put("error", ErrorMessages.EXPIRED_JWT.getMessage()) -// .put("errorCode", 401); -// // Convert JSON object to string -// tempResponse(objectMapper, errorJson, servletResponse); -// return; -// } } - filterChain.doFilter(servletRequest, servletResponse); } - private static void tempResponse(ObjectMapper objectMapper, JsonNode errorJson, HttpServletResponse httpServletResponse) throws IOException { - String jsonString = objectMapper.writeValueAsString(errorJson); - // Set status code and headers - httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); - httpServletResponse.setContentType("application/json; charset=UTF-8"); - httpServletResponse.setCharacterEncoding("UTF-8"); - // Write JSON string to the response body - httpServletResponse.getWriter().write(jsonString); - httpServletResponse.getWriter().flush(); - } - //리퀘스트 헤더에서 토큰 정보를 꺼내온다 private String resolveToken(String authorizationHeader) { if(StringUtils.hasText(authorizationHeader)) { diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/TokenProvider.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/TokenProvider.java index d89b847..8ad3add 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/TokenProvider.java +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/TokenProvider.java @@ -8,10 +8,14 @@ import com.kernel360.orury.domain.user.db.UserEntity; import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.exception.TokenExpiredException; -import com.kernel360.orury.global.exception.TokenNotFoundException; -import com.kernel360.orury.global.message.errors.ErrorMessages; -import io.jsonwebtoken.*; +import com.kernel360.orury.global.error.code.CertificationErrorCode; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; @@ -54,7 +58,7 @@ public TokenProvider( @Value("${jwt.secret}") String secret, UserRepository userRepository, RefreshTokenRepository tokenRepository - ) { + ) { this.refreshValidityMs = refershValiditySec * 1000L; this.accessValidityMs = accessValiditySec * 1000L; this.secret = secret; @@ -69,52 +73,51 @@ public void afterPropertiesSet() { this.key = Keys.hmacShaKeyFor(keyBytes); } - - - public String createAccessToken(Authentication authentication){ + public String createAccessToken(Authentication authentication) { String authorities = authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.joining(",")); + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); long now = (new Date()).getTime(); Date validity = new Date(now + accessValidityMs); UserEntity user = userRepository.findByEmailAddr(authentication.getName()).orElseThrow( - ()-> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage()) + () -> new RuntimeException(UserErrorCode.THERE_IS_NO_USER.getMessage()) ); return Jwts.builder() - .claim(Constant.USERID.getMessage(), user.getId()) - .setSubject(authentication.getName()) - .claim(AUTHORITIES_KEY, authorities) - .signWith(key, SignatureAlgorithm.HS512) - .setExpiration(validity) - .compact(); + .claim(Constant.USERID.getMessage(), user.getId()) + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); } - public String createRefreshToken(Authentication authentication){ + + public String createRefreshToken(Authentication authentication) { long now = (new Date()).getTime(); Date validity = new Date(now + this.refreshValidityMs); // var userId = userRepository.findByEmailAddr(authentication.getName()).orElseThrow( - ()-> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage()) + () -> new BusinessException(UserErrorCode.THERE_IS_NO_USER) ).getId(); return Jwts.builder() - .claim( Constant.USERID.getMessage(), userId) - .signWith(key, SignatureAlgorithm.HS512) - .setExpiration(validity) - .compact(); + .claim(Constant.USERID.getMessage(), userId) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); } // 토큰을 파라미터로 받아서 클레임을 만들고 이를 이용해 유저 객체를 만들고 Authentication 객체 리턴 public Authentication getAuthentication(String token) throws JsonProcessingException { -// Claims claims = Jwts -// .parserBuilder() -// .setSigningKey(key) -// .build() -// .parseClaimsJws(token) -// .getBody(); - + // Claims claims = Jwts + // .parserBuilder() + // .setSigningKey(key) + // .build() + // .parseClaimsJws(token) + // .getBody(); + String[] chunks = token.split("\\."); String payload = new String(Base64.getUrlDecoder().decode(chunks[1])); @@ -123,7 +126,7 @@ public Authentication getAuthentication(String token) throws JsonProcessingExcep JsonNode jsonNode = objectMapper.readTree(payload); // 필요한 정보 추출 -// String userId = jsonNode.get("userId").asText(); + // String userId = jsonNode.get("userId").asText(); String sub = jsonNode.get("sub").asText(); String auth = jsonNode.get("auth").asText(); @@ -137,52 +140,60 @@ public Authentication getAuthentication(String token) throws JsonProcessingExcep return new UsernamePasswordAuthenticationToken(principal, token, authorities); } - - public boolean validateToken(String token ) throws ExpiredJwtException{ + public boolean validateToken(String token) throws ExpiredJwtException { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } - public void storeToken(String token){ + public void storeToken(String token) { Claims claims = Jwts - .parserBuilder() - .setSigningKey(key) - .build() - .parseClaimsJws(token) - .getBody(); + .parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); var userId = Long.parseLong(claims.get("userId").toString()); var user = userRepository.findById(userId).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage()) + () -> new BusinessException(UserErrorCode.THERE_IS_NO_USER) ); RefreshTokenEntity existingToken = refreshTokenRepository.findByUserId(userId).orElse(null); - if(existingToken != null){ + if (existingToken != null) { refreshTokenRepository.delete(existingToken); } var expiredDate = claims.getExpiration().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); var refreshTokenEntity = RefreshTokenEntity.builder() - .tokenValue(token) - .user(user) - .expirationDate(expiredDate) - .build(); + .tokenValue(token) + .user(user) + .expirationDate(expiredDate) + .build(); refreshTokenRepository.save(refreshTokenEntity); } public boolean validateRefreshToken(String refreshToken) { var refreshTokenEntity = refreshTokenRepository.findByTokenValue(refreshToken).orElseThrow( - () -> new TokenNotFoundException(ErrorMessages.ILLEGAL_REFRESH_JWT.getMessage()) + () -> new BusinessException(CertificationErrorCode.ILLEGAL_REFRESH_JWT) ); var expireDate = refreshTokenEntity.getExpirationDate(); if (LocalDateTime.now().isAfter(expireDate)) { - throw new TokenExpiredException(ErrorMessages.EXPIRED_REFRESH_JWT.getMessage()); + throw new BusinessException(CertificationErrorCode.EXPIRED_REFRESH_JWT); } return validateToken(refreshToken); } + public boolean isTokenExpired(String token) { + Date expirationDate = Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody() + .getExpiration(); + return expirationDate.before(new Date()); + } } \ No newline at end of file diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtAuthenticationEntryPoint.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..6ebb636 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtAuthenticationEntryPoint.java @@ -0,0 +1,21 @@ +package com.kernel360.orury.config.jwt.admin; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +@Component +public class AdminJwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 유효한 자격증명을 제공하지 않고 접근하려 할때 redirect + response.sendRedirect("/admin/login"); + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtFilter.java b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtFilter.java new file mode 100644 index 0000000..55f4b63 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/config/jwt/admin/AdminJwtFilter.java @@ -0,0 +1,92 @@ +package com.kernel360.orury.config.jwt.admin; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import com.kernel360.orury.config.jwt.TokenProvider; + +import io.jsonwebtoken.ExpiredJwtException; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AdminJwtFilter extends OncePerRequestFilter { + + private final TokenProvider tokenProvider; + private final String cookieName; + private final String cookieRefreshName; + private final String accessCookieMaxAge; + private final String refreshCookieMaxAge; + + //토큰의 인증정보를 SecurityContext에 저장 + @Override + public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws + IOException, + ServletException { + try { + String accessToken = resolveToken(request, cookieName); + tokenProvider.validateToken(accessToken); + Authentication authentication = tokenProvider.getAuthentication(accessToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + } catch (ExpiredJwtException e) { + try { + String accessToken = resolveToken(request, cookieName); + String refreshToken = resolveToken(request, cookieRefreshName); + tokenProvider.validateToken(refreshToken); + Authentication authentication = tokenProvider.getAuthentication(accessToken); + String newAccessToken = tokenProvider.createAccessToken(authentication); + Cookie accessTokenCookie = new Cookie(cookieName, newAccessToken); + + accessTokenCookie.setHttpOnly(true); + accessTokenCookie.setMaxAge(60 * 60 * 24); + accessTokenCookie.setPath("/"); + + response.addCookie(accessTokenCookie); + + Authentication newAuthentication = tokenProvider.getAuthentication(newAccessToken); + SecurityContextHolder.getContext().setAuthentication(newAuthentication); + } catch (ExpiredJwtException ex) { + clearAuthenticationAndCookie(response); + } + } catch (IllegalArgumentException ignored) { + } + filterChain.doFilter(request, response); + } + + //리퀘스트 헤더에서 토큰 정보를 꺼내온다 + private String resolveToken(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookieName.equals(cookie.getName())) { // 쿠키 이름에 따라서 변경 + return cookie.getValue(); + } + } + } + return null; + } + + private void clearAuthenticationAndCookie(HttpServletResponse response) { + SecurityContextHolder.clearContext(); + Cookie accessCookie = new Cookie(cookieName, null); + accessCookie.setPath("/"); + accessCookie.setHttpOnly(true); + accessCookie.setMaxAge(0); + response.addCookie(accessCookie); + Cookie refreshCookie = new Cookie(cookieRefreshName, null); + refreshCookie.setPath("/"); + refreshCookie.setHttpOnly(true); + refreshCookie.setMaxAge(0); + response.addCookie(refreshCookie); + } +} + diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminAuthController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminAuthController.java new file mode 100644 index 0000000..152ea1d --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminAuthController.java @@ -0,0 +1,91 @@ +package com.kernel360.orury.domain.admin.controller; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.kernel360.orury.config.jwt.TokenProvider; + +@Controller +@RequestMapping("/admin") +public class AdminAuthController { + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + @Value("${jwt.cookie-name}") + private String cookieName; + @Value("${jwt.refresh-cookie-name}") + private String cookieRefreshName; + @Value("${jwt.access-validity}") + private String accessCookieMaxAge; + @Value("${jwt.refresh-validity}") + private String refreshCookieMaxAge; + + public AdminAuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { + this.tokenProvider = tokenProvider; + this.authenticationManagerBuilder = authenticationManagerBuilder; + } + + @GetMapping("/login") + public String login() { + return "pages-login"; + } + + @PostMapping("/login") + public String authenticate(@Valid @RequestParam String emailAddr, String password, + HttpServletResponse response) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(emailAddr, password); + + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + + String accessToken = tokenProvider.createAccessToken(authentication); + String refreshToken = tokenProvider.createRefreshToken(authentication); + tokenProvider.storeToken(refreshToken); + + Cookie accessTokenCookie = new Cookie(cookieName, accessToken); + Cookie refreshTokenCookie = new Cookie(cookieRefreshName, refreshToken); + + accessTokenCookie.setHttpOnly(true); + accessTokenCookie.setMaxAge(Integer.parseInt(accessCookieMaxAge) * 1000); + accessTokenCookie.setPath("/"); + refreshTokenCookie.setHttpOnly(true); + refreshTokenCookie.setMaxAge(Integer.parseInt(refreshCookieMaxAge)); + refreshTokenCookie.setPath("/"); + + response.addCookie(accessTokenCookie); + response.addCookie(refreshTokenCookie); + + return "redirect:/admin/board"; + } + + @PostMapping("/logout") + public String logout(HttpServletResponse response) { + SecurityContextHolder.clearContext(); + Cookie accessCookie = new Cookie(cookieName, null); + accessCookie.setPath("/"); + accessCookie.setHttpOnly(true); + accessCookie.setMaxAge(0); + response.addCookie(accessCookie); + Cookie refreshCookie = new Cookie(cookieRefreshName, null); + refreshCookie.setPath("/"); + refreshCookie.setHttpOnly(true); + refreshCookie.setMaxAge(0); + response.addCookie(refreshCookie); + + return "redirect:/admin/login"; + } +} + diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminBoardController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminBoardController.java index c7070a7..c35a5a5 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminBoardController.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminBoardController.java @@ -25,11 +25,6 @@ public class AdminBoardController { private final BoardService boardService; - @GetMapping - public String index() { - return "index"; - } - @GetMapping("/board") public String board(Model model) { List boardList = boardService.getBoardList(); diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminPostController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminPostController.java index 6063c50..a9c0c7c 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminPostController.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminPostController.java @@ -2,24 +2,17 @@ import java.util.List; -import javax.validation.Valid; - import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.kernel360.orury.domain.admin.service.AdminPostService; -import com.kernel360.orury.domain.board.model.BoardDto; -import com.kernel360.orury.domain.board.model.BoardRequest; -import com.kernel360.orury.domain.board.service.BoardService; import com.kernel360.orury.domain.post.model.PostDto; import com.kernel360.orury.domain.post.model.PostRequest; -import com.kernel360.orury.domain.post.service.PostService; import lombok.RequiredArgsConstructor; diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminUserController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminUserController.java index 99cf1f9..5977aaa 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminUserController.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/controller/AdminUserController.java @@ -1,21 +1,17 @@ package com.kernel360.orury.domain.admin.controller; -import java.awt.image.BufferStrategy; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.kernel360.orury.domain.admin.service.AdminUserService; -import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.domain.user.model.UserDto; -import lombok.Getter; import lombok.RequiredArgsConstructor; @Controller diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminCommentService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminCommentService.java index eb3abb6..7afdcf5 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminCommentService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminCommentService.java @@ -1,13 +1,5 @@ package com.kernel360.orury.domain.admin.service; -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; - -import javax.servlet.http.PushBuilder; - -import org.springframework.stereotype.Service; - import com.kernel360.orury.domain.comment.db.CommentEntity; import com.kernel360.orury.domain.comment.db.CommentRepository; import com.kernel360.orury.domain.comment.model.CommentDto; @@ -17,9 +9,13 @@ import com.kernel360.orury.domain.post.db.PostRepository; import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; - +import com.kernel360.orury.global.error.code.PostErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; @Service @RequiredArgsConstructor @@ -32,7 +28,8 @@ public class AdminCommentService { public CommentDto createComment(CommentRequest commentRequest) { PostEntity postEntity = postRepository.findById(commentRequest.getPostId()) .orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + commentRequest.getPostId())); + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST) + ); CommentEntity commentEntity = CommentEntity.builder() .userId(commentRequest.getUserId()) diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminPostService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminPostService.java index 95bd13d..6b51d01 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminPostService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminPostService.java @@ -1,12 +1,5 @@ package com.kernel360.orury.domain.admin.service; -import java.time.LocalDateTime; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; - -import org.springframework.stereotype.Service; - import com.kernel360.orury.domain.board.db.BoardRepository; import com.kernel360.orury.domain.post.db.PostEntity; import com.kernel360.orury.domain.post.db.PostRepository; @@ -15,9 +8,15 @@ import com.kernel360.orury.domain.post.service.PostConverter; import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; - +import com.kernel360.orury.global.error.code.BoardErrorCode; +import com.kernel360.orury.global.error.code.PostErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; @RequiredArgsConstructor @Service @@ -32,15 +31,13 @@ public PostDto createPost( PostRequest postRequest ) { var boardEntity = boardRepository.findById(postRequest.getBoardId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage())); + .orElseThrow(() -> new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD)); var entity = PostEntity.builder() .postTitle(postRequest.getPostTitle()) .postContent(postRequest.getPostContent()) .userId(1L) .board(boardEntity) - // .thumbnailUrl(postRequest.getPostImageList().isEmpty() ? null : postRequest.getPostImageList().get(0)) - // .images(postRequest.getPostImageList().isEmpty() ? null : String.join(",", postRequest.getPostImageList())) .createdBy(Constant.ADMIN.getMessage()) .createdAt(LocalDateTime.now()) .updatedBy(Constant.ADMIN.getMessage()) @@ -54,7 +51,7 @@ public PostDto createPost( public PostDto getPost(Long id) { Optional postEntityOptional = postRepository.findById(id); PostEntity post = postEntityOptional.orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + id)); + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST)); return postConverter.toDto(post); } @@ -64,7 +61,7 @@ public PostDto updatePost( Long postId = postRequest.getId(); var postEntityOptional = postRepository.findById(postId); var entity = postEntityOptional.orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + postId)); + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST)); var dto = postConverter.toDto(entity); dto.setPostTitle(postRequest.getPostTitle()); dto.setPostContent(postRequest.getPostContent()); diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminUserService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminUserService.java index 27191a3..46cb06f 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminUserService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/admin/service/AdminUserService.java @@ -11,7 +11,6 @@ import com.kernel360.orury.domain.user.db.UserEntity; import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.domain.user.model.UserDto; -import com.kernel360.orury.global.exception.NotFoundMemberException; import lombok.RequiredArgsConstructor; diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/board/service/BoardService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/board/service/BoardService.java index 8c025a5..5920c44 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/board/service/BoardService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/board/service/BoardService.java @@ -4,12 +4,12 @@ import com.kernel360.orury.domain.board.db.BoardRepository; import com.kernel360.orury.domain.board.model.BoardDto; import com.kernel360.orury.domain.board.model.BoardRequest; -import com.kernel360.orury.domain.post.db.PostEntity; import com.kernel360.orury.domain.post.db.PostRepository; import com.kernel360.orury.domain.post.model.PostDto; import com.kernel360.orury.domain.post.service.PostConverter; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.BoardErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -54,7 +54,7 @@ public BoardDto updateBoard( BoardRequest boardRequest ) { BoardEntity entity = boardRepository.findById(boardRequest.getId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage() + boardRequest.getId())); + .orElseThrow(() -> new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD)); BoardDto updatedDto = boardConverter.toDto(entity); updatedDto.setBoardTitle(boardRequest.getBoardTitle()); @@ -72,7 +72,7 @@ public void deleteBoard(Long id) { public BoardDto getBoard(Long id) { var entity = boardRepository.findById(id) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage() + id)); + .orElseThrow(() -> new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD)); return boardConverter.toDto(entity); } @@ -80,7 +80,7 @@ public BoardDto getBoard(Long id) { public List getNoticeBoard(Long id) { var noticeList = postRepository.findAllByBoardId(id); if(noticeList.isEmpty()) { - new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage() + id); + throw new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD); } return noticeList.stream() diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/controller/CommentController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/controller/CommentController.java index 8fd046f..f519ae4 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/controller/CommentController.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/controller/CommentController.java @@ -5,10 +5,8 @@ import com.kernel360.orury.domain.comment.model.CommentLikeRequest; import com.kernel360.orury.domain.comment.model.CommentRequest; import com.kernel360.orury.domain.comment.service.CommentService; -import com.kernel360.orury.domain.post.model.PostLikeRequest; -import com.kernel360.orury.global.common.ApiResponse; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.AuthorizationErrorCode; import com.kernel360.orury.global.message.info.InfoMessages; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -54,7 +52,7 @@ public ResponseEntity updateComment( commentService.updateComment(commentRequest); return ResponseEntity.ok(InfoMessages.COMMENT_UPDATED.getMessage()); } else - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorMessages.THERE_IS_NO_AUTHORITY.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(AuthorizationErrorCode.THERE_IS_NO_AUTHORITY.getMessage()); } // 댓글 삭제 @@ -74,7 +72,7 @@ public ResponseEntity deleteComment( return ResponseEntity.ok(InfoMessages.COMMENT_DELETED.getMessage()); }else{ return ResponseEntity.status(HttpStatus.FORBIDDEN).body( - "댓글 삭제" + ErrorMessages.THERE_IS_NO_AUTHORITY.getMessage()); + "댓글 삭제" + AuthorizationErrorCode.THERE_IS_NO_AUTHORITY.getMessage()); } } diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentConverter.java b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentConverter.java index 3fc16c0..2cf9693 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentConverter.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentConverter.java @@ -9,17 +9,14 @@ import com.kernel360.orury.domain.post.db.PostRepository; import com.kernel360.orury.domain.user.db.UserEntity; import com.kernel360.orury.domain.user.db.UserRepository; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.PostErrorCode; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.NoSuchElementException; - @Service @RequiredArgsConstructor public class CommentConverter { @@ -33,7 +30,7 @@ public CommentDto toDto(CommentEntity commentEntity) { try { // 유저 닉네임 할당 UserEntity userEntity = userRepository.findById(commentEntity.getUserId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage() + commentEntity.getUserId())); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); // 로그인 유저 좋아요 여부 판단 long loginId = getLoginId(); @@ -57,8 +54,7 @@ public CommentDto toDto(CommentEntity commentEntity) { .build(); } catch (Exception e) { // 예외가 발생한 경우 JSON 형식의 응답을 생성 - String errorMessage = ErrorMessages.THERE_IS_NO_USER.getMessage(); - throw new RuntimeException(errorMessage); + throw new BusinessException(UserErrorCode.THERE_IS_NO_USER); } } @@ -66,7 +62,7 @@ public CommentDto toDto(CommentEntity commentEntity) { public CommentEntity toEntity(CommentDto commentdto) { PostEntity postEntity = postRepository.findById(commentdto.getPostId()) .orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + commentdto.getPostId()) + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST) ); return CommentEntity.builder() .id(commentdto.getId()) @@ -100,7 +96,7 @@ private long getLoginId() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String loginEmail = authentication.getName(); UserEntity loginUser = userRepository.findByEmailAddr(loginEmail) - .orElseThrow(() -> new NoSuchElementException(ErrorMessages.THERE_IS_NO_USER.getMessage() + loginEmail)); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); return loginUser.getId(); } } diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentService.java index a2b880a..f5ffc55 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/comment/service/CommentService.java @@ -7,16 +7,15 @@ import com.kernel360.orury.domain.comment.model.CommentRequest; import com.kernel360.orury.domain.notification.service.NotifyService; import com.kernel360.orury.domain.post.db.PostEntity; -import com.kernel360.orury.domain.post.db.PostLikeEntity; -import com.kernel360.orury.domain.post.db.PostLikePK; import com.kernel360.orury.domain.post.db.PostRepository; -import com.kernel360.orury.domain.post.model.PostLikeRequest; import com.kernel360.orury.domain.user.db.UserRepository; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.CommentErrorCode; +import com.kernel360.orury.global.error.code.PostErrorCode; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.time.LocalDateTime; import java.util.List; @@ -40,9 +39,9 @@ public class CommentService { public CommentDto createComment(CommentRequest commentRequest, String userEmail) { PostEntity postEntity = postRepository.findById(commentRequest.getPostId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + commentRequest.getPostId())); + .orElseThrow(() -> new BusinessException(PostErrorCode.THERE_IS_NO_POST)); var user = userRepository.findByEmailAddr(userEmail) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage() + userEmail)); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); Long userId = user.getId(); CommentEntity commentEntity = CommentEntity.builder() @@ -63,7 +62,7 @@ public CommentDto createComment(CommentRequest commentRequest, String userEmail) Long notifyUserId = null; if( commentEntity.getPId() != null ) { notifyUserId = commentRepository.findById(commentEntity.getPId()).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_COMMENT.getMessage() + commentEntity.getPId()) + () -> new BusinessException(CommentErrorCode.THERE_IS_NO_COMMENT) ).getUserId(); if (!Objects.equals(notifyUserId, saveEntity.getUserId())) { sendNotificationToPostAuthor(notifyUserId, postEntity.getPostTitle() + "의 댓글 답변 달림"); @@ -90,7 +89,7 @@ public CommentDto updateComment( ){ Long id = commentRequest.getId(); Optional entity = commentRepository.findById(id); - CommentEntity updateEntity = entity.orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_COMMENT.getMessage() + id)); + CommentEntity updateEntity = entity.orElseThrow(() -> new BusinessException(CommentErrorCode.THERE_IS_NO_COMMENT)); CommentDto updateDto = commentConverter.toDto(updateEntity); updateDto.setCommentContent(commentRequest.getCommentContent()); updateDto.setUpdatedBy(Constant.ADMIN.getMessage()); @@ -114,10 +113,10 @@ public List findAllByPostId(Long postId) { public boolean isWriter(String userEmail, Long id) { var comment = commentRepository.findById(id).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_COMMENT.getMessage() + id) + () -> new BusinessException(CommentErrorCode.THERE_IS_NO_COMMENT) ); var user = userRepository.findByEmailAddr(userEmail).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage() + userEmail) + () -> new BusinessException(UserErrorCode.THERE_IS_NO_USER) ); return Objects.equals(user.getId(), comment.getUserId()); } diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/post/controller/PostController.java b/backend/orury/src/main/java/com/kernel360/orury/domain/post/controller/PostController.java index bcd6b16..d8cfc72 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/post/controller/PostController.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/post/controller/PostController.java @@ -1,21 +1,14 @@ package com.kernel360.orury.domain.post.controller; -import com.kernel360.orury.config.jwt.TokenProvider; import com.kernel360.orury.domain.post.model.PostDto; import com.kernel360.orury.domain.post.model.PostLikeDto; import com.kernel360.orury.domain.post.model.PostLikeRequest; import com.kernel360.orury.domain.post.model.PostRequest; import com.kernel360.orury.domain.post.service.PostService; - import com.kernel360.orury.global.common.Api; - -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.AuthorizationErrorCode; import com.kernel360.orury.global.message.info.InfoMessages; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; import lombok.RequiredArgsConstructor; - -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; @@ -27,8 +20,6 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; - -import java.security.Key; import java.util.Collection; import java.util.List; @@ -98,7 +89,7 @@ public ResponseEntity deletePost(@PathVariable Long postId) { postService.deletePost(postId); return ResponseEntity.ok(InfoMessages.POST_DELETED.getMessage() + postId); }else{ - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("삭제 "+ ErrorMessages.THERE_IS_NO_AUTHORITY.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("삭제 "+ AuthorizationErrorCode.THERE_IS_NO_AUTHORITY.getMessage()); } } diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/post/model/PostDto.java b/backend/orury/src/main/java/com/kernel360/orury/domain/post/model/PostDto.java index 5d931f8..a2d78d1 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/post/model/PostDto.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/post/model/PostDto.java @@ -33,6 +33,7 @@ public class PostDto { private LocalDateTime updatedAt; private String thumbnailUrl; private List imageList = List.of(); + private Long commentCnt; private List commentList = List.of(); private Map> commentMap = Map.of(); @JsonProperty("is_like") diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostConverter.java b/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostConverter.java index bad64c8..af8313b 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostConverter.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostConverter.java @@ -2,9 +2,7 @@ import com.kernel360.orury.domain.board.db.BoardEntity; import com.kernel360.orury.domain.board.db.BoardRepository; -import com.kernel360.orury.domain.board.model.BoardDto; import com.kernel360.orury.domain.comment.model.CommentDto; -import com.kernel360.orury.domain.comment.model.CommentLikeDto; import com.kernel360.orury.domain.comment.service.CommentConverter; import com.kernel360.orury.domain.post.db.PostEntity; import com.kernel360.orury.domain.post.db.PostLikeEntity; @@ -13,7 +11,9 @@ import com.kernel360.orury.domain.post.model.PostLikeDto; import com.kernel360.orury.domain.user.db.UserEntity; import com.kernel360.orury.domain.user.db.UserRepository; -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.global.error.code.BoardErrorCode; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -40,6 +40,8 @@ public PostDto toDto(PostEntity postEntity) { .map(commentConverter::toDto) .toList(); + long commentCnt = commentList.size(); + // map으로 변환 Map> commentMap = new HashMap<>(); for (CommentDto comment : commentList) { @@ -54,7 +56,7 @@ public PostDto toDto(PostEntity postEntity) { // 게시글 작성자 userNickname 설정을 위한 entity UserEntity userEntity = userRepository.findById(postEntity.getUserId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage() + postEntity.getUserId())); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); // 좋아요 수 및 유저 좋아요 세팅 long loginId = getLoginId(); @@ -73,7 +75,9 @@ public PostDto toDto(PostEntity postEntity) { .thumbnailUrl(postEntity.getThumbnailUrl()) .imageList(postEntity.getImages() == null ? List.of() : Arrays.stream(postEntity.getImages().split(",")) .map(image -> getenv().get("IMGUR_URL") + image) - .collect(Collectors.toList())) + .collect(Collectors.toList()) + ) + .commentCnt(commentCnt) .commentList(commentList) .commentMap(commentMap) .isLike(isLike) @@ -88,7 +92,7 @@ public PostDto toDto(PostEntity postEntity) { public PostEntity toEntity(PostDto postDto) { BoardEntity boardEntity = boardRepository.findById(postDto.getBoardId()) .orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage() + postDto.getBoardId()) + () -> new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD) ); return PostEntity.builder() @@ -129,7 +133,7 @@ private long getLoginId() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String loginEmail = authentication.getName(); UserEntity loginUser = userRepository.findByEmailAddr(loginEmail) - .orElseThrow(() -> new NoSuchElementException(ErrorMessages.THERE_IS_NO_USER.getMessage() + loginEmail)); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); return loginUser.getId(); } diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostService.java index fdcaf5b..7a0a991 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/post/service/PostService.java @@ -11,15 +11,18 @@ import com.kernel360.orury.global.common.Api; import com.kernel360.orury.global.common.Pagination; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; - +import com.kernel360.orury.global.error.code.BoardErrorCode; +import com.kernel360.orury.global.error.code.PostErrorCode; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; - import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.*; +import java.util.List; +import java.util.Objects; +import java.util.Optional; @RequiredArgsConstructor @Service @@ -35,10 +38,10 @@ public PostDto createPost( String userEmail ) { var user = userRepository.findByEmailAddr(userEmail) - .orElseThrow(() -> new NoSuchElementException(ErrorMessages.THERE_IS_NO_USER.getMessage() + userEmail)); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); var boardEntity = boardRepository.findById(postRequest.getBoardId()) - .orElseThrow(() -> new RuntimeException(ErrorMessages.THERE_IS_NO_BOARD.getMessage())); + .orElseThrow(() -> new BusinessException(BoardErrorCode.THERE_IS_NO_BOARD)); var entity = PostEntity.builder() .postTitle(postRequest.getPostTitle()) @@ -60,7 +63,7 @@ public PostDto createPost( public PostDto getPost(Long id) { Optional postEntityOptional = postRepository.findById(id); PostEntity post = postEntityOptional.orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + id)); + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST)); return postConverter.toDto(post); } @@ -70,7 +73,7 @@ public PostDto updatePost( Long postId = postRequest.getId(); var postEntityOptional = postRepository.findById(postId); var entity = postEntityOptional.orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + postId)); + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST)); var dto = postConverter.toDto(entity); dto.setPostTitle(postRequest.getPostTitle()); dto.setPostContent(postRequest.getPostContent()); @@ -112,11 +115,11 @@ public Api> getPostList(Pageable pageable) { public boolean isWriter(String userEmail, Long postId) { PostEntity post = postRepository.findById(postId).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_POST.getMessage() + postId) + () -> new BusinessException(PostErrorCode.THERE_IS_NO_POST) ); UserEntity user = userRepository.findByEmailAddr(userEmail).orElseThrow( - () -> new RuntimeException(ErrorMessages.THERE_IS_NO_USER.getMessage() + userEmail) + () -> new BusinessException(UserErrorCode.THERE_IS_NO_USER) ); return Objects.equals(user.getId(), post.getUserId()); diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/user/db/UserEntity.java b/backend/orury/src/main/java/com/kernel360/orury/domain/user/db/UserEntity.java index 78e897a..cd18603 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/user/db/UserEntity.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/user/db/UserEntity.java @@ -59,9 +59,7 @@ public class UserEntity extends BaseEntity { private Boolean isWithdrawal; private String withdrawalId; private LocalDateTime withdrawalAt; - private String remark1; - private String remark2; - private String remark3; + private String remark; @ManyToMany @JoinTable( diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/CustomUserDetailsService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/CustomUserDetailsService.java index 4425660..117e74b 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/CustomUserDetailsService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/CustomUserDetailsService.java @@ -1,19 +1,18 @@ package com.kernel360.orury.domain.user.service; -import java.util.List; -import java.util.stream.Collectors; - -import com.kernel360.orury.global.message.errors.ErrorMessages; +import com.kernel360.orury.domain.user.db.UserEntity; +import com.kernel360.orury.domain.user.db.UserRepository; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import com.kernel360.orury.domain.user.db.UserEntity; -import com.kernel360.orury.domain.user.db.UserRepository; +import java.util.List; +import java.util.stream.Collectors; @Component("userDetailsService") public class CustomUserDetailsService implements UserDetailsService { @@ -28,12 +27,12 @@ public CustomUserDetailsService(UserRepository userRepository) { public UserDetails loadUserByUsername(final String emailAddr) { return userRepository.findOneWithAuthoritiesByEmailAddr(emailAddr) .map(user -> createUser(emailAddr, user)) - .orElseThrow(() -> new UsernameNotFoundException(emailAddr + ErrorMessages.NOT_EXIST_USER_EMAIL)); + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)); } private org.springframework.security.core.userdetails.User createUser(String emailAddr, UserEntity user) { if (!user.isActivated()) { - throw new RuntimeException(emailAddr + ErrorMessages.NOT_ACTIVATED); + throw new BusinessException(UserErrorCode.NOT_ACTIVATED); } List grantedAuthorities = user.getAuthorities().stream() diff --git a/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/UserService.java b/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/UserService.java index d91342f..d0178f7 100644 --- a/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/UserService.java +++ b/backend/orury/src/main/java/com/kernel360/orury/domain/user/service/UserService.java @@ -1,22 +1,19 @@ package com.kernel360.orury.domain.user.service; -import java.time.LocalDateTime; -import java.util.Collections; - import com.kernel360.orury.domain.user.db.AuthorityEntity; +import com.kernel360.orury.domain.user.db.UserEntity; +import com.kernel360.orury.domain.user.db.UserRepository; +import com.kernel360.orury.domain.user.model.UserDto; +import com.kernel360.orury.global.common.SecurityUtil; import com.kernel360.orury.global.constants.Constant; -import com.kernel360.orury.global.message.errors.ErrorMessages; -import org.springframework.security.core.userdetails.UsernameNotFoundException; +import com.kernel360.orury.global.error.code.UserErrorCode; +import com.kernel360.orury.global.error.exception.BusinessException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.kernel360.orury.domain.user.db.UserEntity; -import com.kernel360.orury.domain.user.db.UserRepository; -import com.kernel360.orury.global.exception.DuplicateMemberException; -import com.kernel360.orury.global.exception.NotFoundMemberException; -import com.kernel360.orury.domain.user.model.UserDto; -import com.kernel360.orury.global.common.SecurityUtil; +import java.time.LocalDateTime; +import java.util.Collections; @Service public class UserService { @@ -31,7 +28,7 @@ public UserService(UserRepository userRepository, PasswordEncoder passwordEncode @Transactional public UserDto signup(UserDto userDto) { if (userRepository.findOneWithAuthoritiesByEmailAddr(userDto.getEmailAddr()).orElse(null) != null) { - throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + throw new BusinessException(UserErrorCode.ALREADY_EXISTING_USER); } AuthorityEntity authority = AuthorityEntity.builder() @@ -63,14 +60,14 @@ public UserDto getMyUserWithAuthorities() { return UserDto.from( SecurityUtil.getCurrentUsername() .flatMap(userRepository::findOneWithAuthoritiesByEmailAddr) - .orElseThrow(() -> new NotFoundMemberException("Member not found")) + .orElseThrow(() -> new BusinessException(UserErrorCode.THERE_IS_NO_USER)) ); } @Transactional(readOnly = true) public Long getUserIdByEmail(String email){ return userRepository.findByEmailAddr(email).orElseThrow( - () -> new UsernameNotFoundException(ErrorMessages.THERE_IS_NO_USER.getMessage()) + () -> new BusinessException(UserErrorCode.THERE_IS_NO_USER) ).getId(); } diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/GlobalExceptionHandler.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/GlobalExceptionHandler.java new file mode 100644 index 0000000..a6c66af --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/GlobalExceptionHandler.java @@ -0,0 +1,24 @@ +package com.kernel360.orury.global.error; + +import com.kernel360.orury.global.common.ApiResponse; +import com.kernel360.orury.global.error.code.ServerErrorCode; +import com.kernel360.orury.global.error.dto.ErrorResponse; +import com.kernel360.orury.global.error.exception.BusinessException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(BusinessException.class) + public ResponseEntity handleBusinessException(BusinessException e) { + return ResponseEntity.status(e.getErrorCode().getStatus()).body(ErrorResponse.of(e.getErrorCode())); + } + +// @ExceptionHandler(Exception.class) +// public ResponseEntity handleException(Exception e){ +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(HttpStatus.INTERNAL_SERVER_ERROR, 500, ServerErrorCode.INTERNAL_SERVER_ERROR.getMessage())); +// } + +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/AuthorizationErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/AuthorizationErrorCode.java new file mode 100644 index 0000000..90dd832 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/AuthorizationErrorCode.java @@ -0,0 +1,25 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum AuthorizationErrorCode implements ErrorCode { + THERE_IS_NO_AUTHORITY(403, 403, "권한이 없습니다"); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/BoardErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/BoardErrorCode.java new file mode 100644 index 0000000..850b796 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/BoardErrorCode.java @@ -0,0 +1,26 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum BoardErrorCode implements ErrorCode { + THERE_IS_NO_BOARD(400, 410, "해당 게시판이 존재하지 않습니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} + diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CertificationErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CertificationErrorCode.java new file mode 100644 index 0000000..858c473 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CertificationErrorCode.java @@ -0,0 +1,30 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum CertificationErrorCode implements ErrorCode { + MALFORMED_JWT(401, 401, "잘못된 JWT 서명입니다."), + EXPIRED_ACCESS_JWT(401, 411, "만료된 Access Token 입니다."), + UNSUPPORTED_JWT(401, 401, "지원되지 않는 JWT 토큰입니다."), + EXPIRED_REFRESH_JWT(401, 412, "만료된 Refresh Token 입니다."), + ILLEGAL_ARGUMENT_JWT(401, 401, "JWT 토큰이 잘못되었습니다."), + ILLEGAL_REFRESH_JWT(401, 401, "유효하지 않은 Refresh Token 입니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CommentErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CommentErrorCode.java new file mode 100644 index 0000000..f784d28 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/CommentErrorCode.java @@ -0,0 +1,25 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum CommentErrorCode implements ErrorCode{ + THERE_IS_NO_COMMENT(400, 430, "해당 댓글이 존재하지 않습니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ErrorCode.java new file mode 100644 index 0000000..2b9a474 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ErrorCode.java @@ -0,0 +1,7 @@ +package com.kernel360.orury.global.error.code; + +public interface ErrorCode { + int getStatus(); + int getCode(); + String getMessage(); +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/PostErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/PostErrorCode.java new file mode 100644 index 0000000..98c6e25 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/PostErrorCode.java @@ -0,0 +1,25 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum PostErrorCode implements ErrorCode { + THERE_IS_NO_POST(400, 420, "해당 게시글이 존재하지 않습니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ServerErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ServerErrorCode.java new file mode 100644 index 0000000..460407c --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/ServerErrorCode.java @@ -0,0 +1,25 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum ServerErrorCode implements ErrorCode { + INTERNAL_SERVER_ERROR(500, 500, "서버 에러가 발생했습니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/code/UserErrorCode.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/UserErrorCode.java new file mode 100644 index 0000000..b25ca94 --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/code/UserErrorCode.java @@ -0,0 +1,27 @@ +package com.kernel360.orury.global.error.code; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum UserErrorCode implements ErrorCode { + THERE_IS_NO_USER(400, 400,"해당 유저가 존재하지 않습니다."), + ALREADY_EXISTING_USER(400, 401, "이미 존재하는 유저입니다."), + NOT_ACTIVATED(400, 402, "휴면 처리된 회원입니다."); + + private final int status; + private final int code; + private final String message; + + @Override + public int getStatus() { return status; } + + @Override + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/dto/ErrorResponse.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/dto/ErrorResponse.java new file mode 100644 index 0000000..628376d --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/dto/ErrorResponse.java @@ -0,0 +1,29 @@ +package com.kernel360.orury.global.error.dto; + +import com.kernel360.orury.global.error.code.ErrorCode; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ErrorResponse { +// private int status; + private int code; + private String message; + + @Builder + public ErrorResponse(String message, int code, int status) { +// this.status = status; + this.code = code; + this.message = message; + } + + public static ErrorResponse of(ErrorCode errorCode) { + return ErrorResponse.builder() +// .status(errorCode.getStatus()) + .code(errorCode.getCode()) + .message(errorCode.getMessage()) + .build(); + } +} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/error/exception/BusinessException.java b/backend/orury/src/main/java/com/kernel360/orury/global/error/exception/BusinessException.java new file mode 100644 index 0000000..e72286d --- /dev/null +++ b/backend/orury/src/main/java/com/kernel360/orury/global/error/exception/BusinessException.java @@ -0,0 +1,14 @@ +package com.kernel360.orury.global.error.exception; + +import com.kernel360.orury.global.error.code.ErrorCode; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public class BusinessException extends RuntimeException { + private final ErrorCode errorCode; + + public BusinessException(ErrorCode errorCode) { + this.errorCode = errorCode; + } +} \ No newline at end of file diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/DuplicateMemberException.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/DuplicateMemberException.java deleted file mode 100644 index a323b52..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/DuplicateMemberException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.kernel360.orury.global.exception; - -public class DuplicateMemberException extends RuntimeException { - - public DuplicateMemberException() { - super(); - } - - public DuplicateMemberException(String message, Throwable cause) { - super(message, cause); - } - - public DuplicateMemberException(String message) { - super(message); - } - - public DuplicateMemberException(Throwable cause) { - super(cause); - } - -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/GlobalExceptionHandler.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/GlobalExceptionHandler.java deleted file mode 100644 index a55a59d..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.kernel360.orury.global.exception; - -import com.kernel360.orury.global.common.ApiResponse; -import com.kernel360.orury.global.message.errors.ErrorMessages; -import io.jsonwebtoken.ExpiredJwtException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -import java.util.NoSuchElementException; - -@RestControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(TokenExpiredException.class) - public ResponseEntity handleTokenExpiredException(TokenExpiredException ex){ - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, ErrorMessages.EXPIRED_JWT.getMessage())); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception ex){ - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(HttpStatus.INTERNAL_SERVER_ERROR, 500, ErrorMessages.INTERNAL_SERVER_ERROR.getMessage())); - } - - @ExceptionHandler(ExpiredJwtException.class) - public ResponseEntity handleTokenExpiredException(ExpiredJwtException ex){ - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, ErrorMessages.EXPIRED_JWT.getMessage())); - } - @ExceptionHandler(TokenNotFoundException.class) - public ResponseEntity handleTokenNotFoundException(TokenNotFoundException ex){ - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ApiResponse.error(HttpStatus.UNAUTHORIZED, 402, ErrorMessages.ILLEGAL_REFRESH_JWT.getMessage())); - } - - @ExceptionHandler({IllegalArgumentException.class, NoSuchElementException.class}) - public ResponseEntity userNotFoundException(NoSuchElementException ex){ - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(HttpStatus.BAD_REQUEST, 400, ErrorMessages.THERE_IS_NO_USER.getMessage())); - } - - @ExceptionHandler(RuntimeException.class) - public ResponseEntity boardNotFoundException(RuntimeException ex){ - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(HttpStatus.BAD_REQUEST, 400, ex.getMessage())); - } - - @ExceptionHandler(RefreshExpiredJwtException.class) - public ResponseEntity handleRefreshTokenExpiredException(RefreshExpiredJwtException ex){ - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ApiResponse.error(HttpStatus.UNAUTHORIZED, 402, ErrorMessages.EXPIRED_REFRESH_JWT.getMessage())); - } -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/NotFoundMemberException.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/NotFoundMemberException.java deleted file mode 100644 index fde361d..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/NotFoundMemberException.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.kernel360.orury.global.exception; - -public class NotFoundMemberException extends RuntimeException { - public NotFoundMemberException() { - super(); - } - - public NotFoundMemberException(String message, Throwable cause) { - super(message, cause); - } - - public NotFoundMemberException(String message) { - super(message); - } - - public NotFoundMemberException(Throwable cause) { - super(cause); - } -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/RefreshExpiredJwtException.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/RefreshExpiredJwtException.java deleted file mode 100644 index 849f15f..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/RefreshExpiredJwtException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kernel360.orury.global.exception; - -public class RefreshExpiredJwtException extends RuntimeException{ - public RefreshExpiredJwtException(String message){ - super(message); - } -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenExpiredException.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenExpiredException.java deleted file mode 100644 index 70ad667..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenExpiredException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kernel360.orury.global.exception; - -public class TokenExpiredException extends RuntimeException{ - public TokenExpiredException(String message) { - super(message); - } -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenNotFoundException.java b/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenNotFoundException.java deleted file mode 100644 index a0e7df7..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/exception/TokenNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kernel360.orury.global.exception; - -public class TokenNotFoundException extends RuntimeException{ - public TokenNotFoundException(String message) { - super(message); - } -} diff --git a/backend/orury/src/main/java/com/kernel360/orury/global/message/errors/ErrorMessages.java b/backend/orury/src/main/java/com/kernel360/orury/global/message/errors/ErrorMessages.java deleted file mode 100644 index 8121fd0..0000000 --- a/backend/orury/src/main/java/com/kernel360/orury/global/message/errors/ErrorMessages.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.kernel360.orury.global.message.errors; - -import lombok.Getter; - -@Getter -public enum ErrorMessages { - // 게시판 - THERE_IS_NO_BOARD("게시판이 존재하지 않습니다."), - THERE_IS_NO_POST("게시글이 존재하지 않습니다."), - THERE_IS_NO_COMMENT("댓글이 존재하지 않습니다."), - THERE_IS_NO_USER("유저가 존재하지 않습니다."), - THERE_IS_NO_AUTHORITY("권한이 없습니다"), - - // 회원 - NOT_EXIST_USER_EMAIL("존재하지 않는 회원입니다. (email 계정 없음)"), - NOT_ACTIVATED("휴면 처리된 회원입니다."), - - // 인증 - MALFORMED_JWT("잘못된 JWT 서명입니다."), - EXPIRED_JWT("만료된 JWT 서명입니다."), - UNSUPPORTED_JWT("지원되지 않는 JWT 토큰입니다."), - EXPIRED_REFRESH_JWT("만료된 REFRESH JWT 서명입니다."), - ILLEGAL_ARGUMENT_JWT("JWT 토큰이 잘못되었습니다."), - ILLEGAL_REFRESH_JWT("유효하지 않은 JWT리프레시 토큰입니다."), - - // 서버 - INTERNAL_SERVER_ERROR("서버 에러가 발생했습니다.") - ; - - private final String message; - - ErrorMessages(String message) { - this.message = message; - } - -} diff --git a/backend/orury/src/main/resources/application.yml b/backend/orury/src/main/resources/application.yml index b5f3b9f..380aa42 100644 --- a/backend/orury/src/main/resources/application.yml +++ b/backend/orury/src/main/resources/application.yml @@ -12,25 +12,36 @@ spring: generate-ddl: true hibernate: ddl-auto: validate + cache: + use_second_level_cache: false + use_query_cache: false properties: hibernate: format_sql: true use_sql_comments: true show_sql: true + persistence: + sharedCache: + mode:NONE datasource: driver-class-name: com.mysql.cj.jdbc.Driver -# url: ${LOCAL_DB_URL} # configuration에서 설정 필요 + # url: ${LOCAL_DB_URL} # configuration에서 설정 필요 url: ENC(4t9k8jNC5SIDd1hpsqRJiw5NgwtRAZ9l2cY42PcN3v6GNDC61KXk4X3nYwwUdW4+aC6g41zh14HyfWg+2fPmfuTXHg7aw+vTvL9Oomq1wEKM2r2ZHJbhmakdpmbeMVjVALC/MSk28Tp4a5sBhUFRWdpaFO2qQcpdUHUd9KsuJh0=) -# username: ${LOCAL_DB_USERNAME} + # username: ${LOCAL_DB_USERNAME} username: ENC(2STroDy2TfWobkrTroFwbRcxLke05156ZFMrqwKmVssNcN4foSX4I6ax8YAgdW3R) -# password: ${LOCAL_DB_USER_PASSWORD} + # password: ${LOCAL_DB_USER_PASSWORD} password: ENC(a8l7l/AYNz2x1HPYyu+urOBwVcBhQkeWgTi6Fvt+lQFq1QyHsL8yyi5+wr7lh26P) + flyway: + enabled: true + baseline-on-migrate: true jwt: header: Authorization #HS512 알고리즘을 사용할 것이기 때문에 512bit, 즉 64byte 이상의 secret key를 사용해야 한다. #echo 'silvernine-tech-spring-boot-jwt-tutorial-secret-silvernine-tech-spring-boot-jwt-tutorial-secret'|base64 -# secret: ${LOCAL_JWT_SECRET_KEY} + # secret: ${LOCAL_JWT_SECRET_KEY} secret: ENC(XNkGVBeK1sJZhLhri+zz7pJOhHCvfif265mvT8OUIbOGeQcOCtHNnG2s3qjsKNe2u+dLoNVQBzbF1bKUfDxi8Po5tL7jQbZMPA33Dg1QMQFQWV46IyrYnLykYXQQvpin/SNPXW04ECDoRLF3TNwcS22D8uWEwe8L2wtcauyHeO1z+J6lUQArPHy76O2pzC7FHlBjOTw3STd23e3dd1WBQtHAYVmOIvNuPreulzSaHXc=) access-validity: 1800 refresh-validity: 7200 + cookie-name: access-token + refresh-cookie-name: refresh-token diff --git a/backend/orury/src/main/resources/data.sql b/backend/orury/src/main/resources/data.sql index 342180b..a8c339c 100644 --- a/backend/orury/src/main/resources/data.sql +++ b/backend/orury/src/main/resources/data.sql @@ -3,9 +3,9 @@ values ('admin@gmail.com', '$2a$08$lDnHPz7eUkSi6ao14Twuau08mzhWrL4kyZGGU5xfiGALO insert into user (email_addr, password, activated, created_at, created_by) values ('shin@gmail.com', '$2a$08$UkVvwpULis18S19S5pZFn.YHPZt3oaqHZnDwqbCW9pft6uFtkXKDC', 1, now(), 'admin'); -insert into authority (authority_name, ) +insert into authority (name) values ('ROLE_USER'); -insert into authority (authority_name) +insert into authority (name) values ('ROLE_ADMIN'); insert into user_authority (user_id, authority_name) diff --git a/backend/orury/src/main/resources/db/migration/V1.0.0__alter_column_in_user.sql b/backend/orury/src/main/resources/db/migration/V1.0.0__alter_column_in_user.sql new file mode 100644 index 0000000..5dcd2df --- /dev/null +++ b/backend/orury/src/main/resources/db/migration/V1.0.0__alter_column_in_user.sql @@ -0,0 +1,6 @@ +-- 기존 remark2, 3 삭제 +alter table user drop column remark2; +alter table user drop column remark3; + +-- remark1 -> remark 변경 +alter table user change remark1 remark varchar(255); diff --git a/backend/orury/src/main/resources/templates/index.html b/backend/orury/src/main/resources/templates/index.html index 6d2ddff..490b6a9 100644 --- a/backend/orury/src/main/resources/templates/index.html +++ b/backend/orury/src/main/resources/templates/index.html @@ -40,7 +40,6 @@ - !-- ======= Header ======= -->