From 24873db317bfde7072bfa0e6bd523e8a7d96aecd Mon Sep 17 00:00:00 2001 From: geonhos Date: Tue, 21 May 2024 14:37:14 +0900 Subject: [PATCH] =?UTF-8?q?admin:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20action?= =?UTF-8?q?=20log=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/admin/AdminActionLogAppService.java | 39 +++++++++++++ .../admin/app/admin/AdminActionLogCreate.java | 21 +++++++ .../admin/app/admin/AdminActionLogUpdate.java | 20 +++++++ .../authorization/AuthorizationService.java | 2 +- .../poc/admin/common/CookieHelper.java | 12 +++- .../bpgroup/poc/admin/common/JwtHelper.java | 19 +++++++ .../base/admin/entity/AdminActionLog.java | 56 +++++++++++++++++++ .../entity/AdminActionLogRepository.java | 9 +++ .../service/AdminActionLogCreateCommand.java | 29 ++++++++++ .../admin/service/AdminActionLogService.java | 33 +++++++++++ .../service/AdminActionLogUpdateCommand.java | 24 ++++++++ .../base/admin/service/AdminService.java | 6 ++ .../poc/admin/filter/LoggingFilter.java | 47 +++++++++++++++- .../security/jwt/JwtTokenValidateFilter.java | 15 +---- 14 files changed, 315 insertions(+), 17 deletions(-) create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogAppService.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogCreate.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogUpdate.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/common/JwtHelper.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLog.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLogRepository.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogCreateCommand.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogService.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogUpdateCommand.java diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogAppService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogAppService.java new file mode 100644 index 0000000..32d4c06 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogAppService.java @@ -0,0 +1,39 @@ +package com.bpgroup.poc.admin.app.admin; + +import com.bpgroup.poc.admin.domain.base.admin.entity.Admin; +import com.bpgroup.poc.admin.domain.base.admin.service.AdminActionLogCreateCommand; +import com.bpgroup.poc.admin.domain.base.admin.service.AdminActionLogService; +import com.bpgroup.poc.admin.domain.base.admin.service.AdminActionLogUpdateCommand; +import com.bpgroup.poc.admin.domain.base.admin.service.AdminService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AdminActionLogAppService { + + private final AdminActionLogService adminActionLogService; + private final AdminService adminService; + + public void create(AdminActionLogCreate.Request request) { + Admin findAdmin = adminService.find(request.getLoginId()).orElseThrow(() -> new IllegalArgumentException("Not found admin")); + adminActionLogService.create( + AdminActionLogCreateCommand.of( + request.getSessionId(), + request.getRequestUri(), + request.getRequestValue(), + findAdmin + ) + ); + } + + public void update(AdminActionLogUpdate.Request request) { + adminActionLogService.update( + AdminActionLogUpdateCommand.of( + request.getSessionId(), + request.getResponseValue() + ) + ); + } + +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogCreate.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogCreate.java new file mode 100644 index 0000000..df8173b --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogCreate.java @@ -0,0 +1,21 @@ +package com.bpgroup.poc.admin.app.admin; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +public class AdminActionLogCreate { + + @Getter + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + public static class Request { + private final String sessionId; + private final String requestUri; + private final String requestValue; + private final String loginId; + + public static Request of(String sessionId, String requestUri, String requestValue, String loginId) { + return new Request(sessionId, requestUri, requestValue, loginId); + } + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogUpdate.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogUpdate.java new file mode 100644 index 0000000..d8f1fd7 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/admin/AdminActionLogUpdate.java @@ -0,0 +1,20 @@ +package com.bpgroup.poc.admin.app.admin; + + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +public class AdminActionLogUpdate { + + @Getter + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + public static class Request { + private final String sessionId; + private final String responseValue; + + public static Request of(String sessionId, String responseValue) { + return new Request(sessionId, responseValue); + } + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/authorization/AuthorizationService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/authorization/AuthorizationService.java index d99e1bc..64cf466 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/authorization/AuthorizationService.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/app/authorization/AuthorizationService.java @@ -25,6 +25,6 @@ public class AuthorizationService { Admin admin = findAdmin.get(); return admin.getAdminRole().getRole().getRoleMenus().stream() - .anyMatch(roleMenu -> roleMenu.getMenu().getUri().equals(requestUri)); + .anyMatch(roleMenu -> requestUri.contains(roleMenu.getMenu().getUri())); } } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/common/CookieHelper.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/common/CookieHelper.java index 6c8d815..9f89197 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/common/CookieHelper.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/common/CookieHelper.java @@ -1,6 +1,5 @@ package com.bpgroup.poc.admin.common; -import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.context.request.RequestContextHolder; @@ -14,9 +13,18 @@ public class CookieHelper { HttpServletRequest request = attr.getRequest(); Cookie[] cookies = request.getCookies(); + return getValue(cookies, name); + } + + public static Optional getValueFromCookieWithName(HttpServletRequest request, String name) { + Cookie[] cookies = request.getCookies(); + return getValue(cookies, name); + } + + private static Optional getValue(Cookie[] cookies, String name) { if (null != cookies) { for (Cookie cookie : cookies) { - if (JwtTokenConstants.NAME.equals(cookie.getName())) { + if (cookie.getName().equals(name)) { return Optional.of(cookie.getValue()); } } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/common/JwtHelper.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/common/JwtHelper.java new file mode 100644 index 0000000..b81af3f --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/common/JwtHelper.java @@ -0,0 +1,19 @@ +package com.bpgroup.poc.admin.common; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; + +public class JwtHelper { + public static Claims getClaims(String jwtKey, String token) { + SecretKey key = Keys.hmacShaKeyFor(jwtKey.getBytes(StandardCharsets.UTF_8)); + return Jwts.parser() + .verifyWith(key) + .build() + .parseSignedClaims(token) + .getPayload(); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLog.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLog.java new file mode 100644 index 0000000..870070c --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLog.java @@ -0,0 +1,56 @@ +package com.bpgroup.poc.admin.domain.base.admin.entity; + +import com.bpgroup.poc.admin.domain.base.BaseEntity; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "admin_action_log") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AdminActionLog extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "session_id", nullable = false) + private String sessionId; + + @Column(name = "request_uri", nullable = false) + private String requestUri; + + @Column(name = "request_value") + private String requestValue; + + @Column(name = "response_value") + private String responseValue; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "admin_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT), nullable = false) + private Admin admin; + + private AdminActionLog(String sessionId, String requestUri, String requestValue, Admin admin) { + this.sessionId = sessionId; + this.requestUri = requestUri; + this.requestValue = requestValue; + this.admin = admin; + } + + private AdminActionLog(String sessionId, String responseValue) { + this.sessionId = sessionId; + this.responseValue = responseValue; + } + + public static AdminActionLog createOf(String sessionId, String requestUri, String requestValue, Admin admin) { + return new AdminActionLog(sessionId, requestUri, requestValue, admin); + } + + public static AdminActionLog updateOf(String sessionId, String responseValue) { + return new AdminActionLog(sessionId, responseValue); + } + + public void update(AdminActionLog entity) { + this.responseValue = entity.responseValue; + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLogRepository.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLogRepository.java new file mode 100644 index 0000000..def66d2 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/entity/AdminActionLogRepository.java @@ -0,0 +1,9 @@ +package com.bpgroup.poc.admin.domain.base.admin.entity; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface AdminActionLogRepository extends JpaRepository { + Optional findBySessionId(String sessionId); +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogCreateCommand.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogCreateCommand.java new file mode 100644 index 0000000..0fac673 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogCreateCommand.java @@ -0,0 +1,29 @@ +package com.bpgroup.poc.admin.domain.base.admin.service; + +import com.bpgroup.poc.admin.domain.base.admin.entity.Admin; +import com.bpgroup.poc.admin.domain.base.admin.entity.AdminActionLog; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class AdminActionLogCreateCommand { + @NotBlank + private final String sessionId; + @NotBlank + private final String requestUri; + private final String requestValue; + @NotNull + private final Admin admin; + + public static AdminActionLogCreateCommand of(String sessionId, String requestUri, String requestValue, Admin admin) { + return new AdminActionLogCreateCommand(sessionId, requestUri, requestValue, admin); + } + + public AdminActionLog toEntity() { + return AdminActionLog.createOf(sessionId, requestUri, requestValue, admin); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogService.java new file mode 100644 index 0000000..c8702f5 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogService.java @@ -0,0 +1,33 @@ +package com.bpgroup.poc.admin.domain.base.admin.service; + +import com.bpgroup.poc.admin.domain.base.admin.entity.AdminActionLog; +import com.bpgroup.poc.admin.domain.base.admin.entity.AdminActionLogRepository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +@Service +@RequiredArgsConstructor +@Validated +@Transactional +public class AdminActionLogService { + + private final AdminActionLogRepository adminActionLogRepository; + + public void create( + @NotNull @Valid AdminActionLogCreateCommand command + ) { + adminActionLogRepository.save(command.toEntity()); + } + + public void update( + @NotNull @Valid AdminActionLogUpdateCommand command + ) { + AdminActionLog findAdminActionLog = adminActionLogRepository.findBySessionId(command.getSessionId()).orElseThrow(() -> new IllegalArgumentException("Not found admin action log")); + findAdminActionLog.update(command.toEntity()); + } + +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogUpdateCommand.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogUpdateCommand.java new file mode 100644 index 0000000..3894647 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminActionLogUpdateCommand.java @@ -0,0 +1,24 @@ +package com.bpgroup.poc.admin.domain.base.admin.service; + +import com.bpgroup.poc.admin.domain.base.admin.entity.AdminActionLog; +import jakarta.validation.constraints.NotBlank; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class AdminActionLogUpdateCommand { + @NotBlank + private final String sessionId; + @NotBlank + private final String responseValue; + + public static AdminActionLogUpdateCommand of(String sessionId, String responseValue) { + return new AdminActionLogUpdateCommand(sessionId, responseValue); + } + + public AdminActionLog toEntity() { + return AdminActionLog.updateOf(sessionId, responseValue); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminService.java index cba0c8f..5843e3e 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminService.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/domain/base/admin/service/AdminService.java @@ -9,6 +9,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.util.Optional; + @Service @RequiredArgsConstructor @Validated @@ -33,4 +35,8 @@ public class AdminService { public void delete(@NotNull Long id) { adminRepository.deleteById(id); } + + public Optional find(String adminId) { + return adminRepository.findByLoginId(adminId); + } } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/filter/LoggingFilter.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/filter/LoggingFilter.java index 636f95a..259fe4f 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/filter/LoggingFilter.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/filter/LoggingFilter.java @@ -1,9 +1,17 @@ package com.bpgroup.poc.admin.filter; +import com.bpgroup.poc.admin.app.admin.AdminActionLogAppService; +import com.bpgroup.poc.admin.app.admin.AdminActionLogCreate; +import com.bpgroup.poc.admin.app.admin.AdminActionLogUpdate; +import com.bpgroup.poc.admin.common.CookieHelper; +import com.bpgroup.poc.admin.common.JwtHelper; +import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants; +import io.jsonwebtoken.Claims; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @@ -14,12 +22,17 @@ import org.springframework.web.util.ContentCachingResponseWrapper; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.stream.Stream; @Slf4j @Order(Ordered.HIGHEST_PRECEDENCE) +@RequiredArgsConstructor @Component public class LoggingFilter extends OncePerRequestFilter { + + private final AdminActionLogAppService adminActionLogAppService; + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { customDoFilter(new ContentCachingRequestWrapper(request), new ContentCachingResponseWrapper(response), filterChain); @@ -38,8 +51,29 @@ public class LoggingFilter extends OncePerRequestFilter { } private void loggingRequest(ContentCachingRequestWrapper request, String sessionId) { + String requestValue = new String(request.getContentAsByteArray(), StandardCharsets.UTF_8); + Optional jwtToken = CookieHelper.getValueFromCookieWithName(request, JwtTokenConstants.NAME); + + if (jwtToken.isPresent()) { + try { + Claims claims = JwtHelper.getClaims(JwtTokenConstants.KEY, jwtToken.get()); + String username = claims.get("username", String.class); + + adminActionLogAppService.create( + AdminActionLogCreate.Request.of( + sessionId, + request.getRequestURI(), + requestValue, + username + ) + ); + } catch (Exception e) { + log.info("session ID: {} Request - JWT 토큰 만료", sessionId); + } + } + log.info("session ID: {} Request - method: {} uri: {}", sessionId, request.getMethod(), request.getRequestURI()); - log.info("session ID: {} Request - params: {}", sessionId, new String(request.getContentAsByteArray(), StandardCharsets.UTF_8)); + log.info("session ID: {} Request - params: {}", sessionId, requestValue); } private void loggingResponse(ContentCachingResponseWrapper response, String sessionId) { @@ -48,7 +82,16 @@ public class LoggingFilter extends OncePerRequestFilter { log.info("Session ID: {} Response - status: {} Content-Type: {}", sessionId, response.getStatus(), contentType); if (contentType != null && isLoggingContentType(contentType)) { - log.info("Session ID: {} Response - body: {}", sessionId, new String(response.getContentAsByteArray(), StandardCharsets.UTF_8)); + String responseValue = new String(response.getContentAsByteArray(), StandardCharsets.UTF_8); + + adminActionLogAppService.update( + AdminActionLogUpdate.Request.of( + sessionId, + responseValue + ) + ); + + log.info("Session ID: {} Response - body: {}", sessionId, responseValue); } } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/jwt/JwtTokenValidateFilter.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/jwt/JwtTokenValidateFilter.java index d62d4d4..e9dd2ec 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/jwt/JwtTokenValidateFilter.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/jwt/JwtTokenValidateFilter.java @@ -1,9 +1,8 @@ package com.bpgroup.poc.admin.security.jwt; import com.bpgroup.poc.admin.common.CookieHelper; +import com.bpgroup.poc.admin.common.JwtHelper; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.security.Keys; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -13,9 +12,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; -import javax.crypto.SecretKey; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.stream.Stream; @@ -27,15 +24,9 @@ public class JwtTokenValidateFilter extends OncePerRequestFilter { try { Optional jwtToken = CookieHelper.getValueFromCookieWithName(JwtTokenConstants.NAME); if (jwtToken.isPresent()) { - SecretKey key = Keys.hmacShaKeyFor(JwtTokenConstants.KEY.getBytes(StandardCharsets.UTF_8)); - - Claims claims = Jwts.parser() - .verifyWith(key) - .build() - .parseSignedClaims(jwtToken.get()) - .getPayload(); - + Claims claims = JwtHelper.getClaims(JwtTokenConstants.KEY, jwtToken.get()); String username = claims.get("username", String.class); + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, null); SecurityContextHolder.getContext().setAuthentication(auth); }