Skip to content
Snippets Groups Projects
Commit 27f195a1 authored by nahyun's avatar nahyun
Browse files

Merge branch 'feat/certificate' into 'main'

Feat/certificate

See merge request !15
parents 53843083 7a143ba4
No related branches found
No related tags found
1 merge request!15Feat/certificate
Showing
with 1142 additions and 0 deletions
FROM gradle:jdk21 AS build
WORKDIR /tmp
RUN wget -O lego.tar.gz "https://github.com/go-acme/lego/releases/download/v4.22.2/lego_v4.22.2_linux_amd64.tar.gz" && tar -xzf lego.tar.gz && rm -f lego.tar.gz
WORKDIR /home/gradle/project
COPY --chown=gradle:gradle build.gradle settings.gradle .
RUN gradle dependencies --no-daemon
COPY --chown=gradle:gradle src ./src
RUN gradle clean bootJar --no-daemon
FROM eclipse-temurin:21-jre-alpine
COPY --from=build /tmp/lego /usr/local/bin/lego
RUN chmod +x /usr/local/bin/lego
WORKDIR /app
COPY --from=build /home/gradle/project/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
......@@ -26,13 +26,23 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
}
tasks.named('test') {
useJUnitPlatform()
}
clean {
delete file('src/main/generated')
}
\ No newline at end of file
......@@ -2,8 +2,10 @@ package com.aolda.itda;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class ItdaApplication {
public static void main(String[] args) {
......
package com.aolda.itda.aspect;
import com.aolda.itda.dto.certificate.CertificateDTO;
import com.aolda.itda.entity.certificate.Certificate;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.Log;
import com.aolda.itda.entity.log.ObjectType;
import com.aolda.itda.entity.user.User;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.certificate.CertificateRepository;
import com.aolda.itda.repository.log.LogRepository;
import com.aolda.itda.repository.user.UserRepository;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
@RequiredArgsConstructor
public class CertificateLogAspect {
private final CertificateRepository certificateRepository;
private final UserRepository userRepository;
private final LogRepository logRepository;
private final EntityManager entityManager;
private static final DateTimeFormatter LOG_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/* Create 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.certificate.*Service.*create*(..))"
, returning = "result")
public void createLogging(JoinPoint joinPoint, CertificateDTO result) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 생성된 엔티티 조회 */
Certificate certificate = certificateRepository.findByCertificateIdAndIsDeleted(result.getId(), false).orElse(null);
/* 로그 메세지 작성 */
String description = "domain: " + certificate.getDomain() + "\n"
+ "email: " + certificate.getEmail() + "\n"
+ "challenge: " + certificate.getChallenge() + "\n"
+ "expiresAt: " + (certificate.getExpiresAt() != null ? certificate.getExpiresAt().format(LOG_DATE_FORMATTER) : "null");
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.CERTIFICATE)
.objectId(certificate.getCertificateId())
.action(Action.CREATE)
.projectId(certificate.getProjectId())
.description(description)
.build());
}
/* Delete 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.certificate.*Service.*delete*(..))")
public void deleteLogging(JoinPoint joinPoint) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 삭제된 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Certificate certificate = certificateRepository.findByCertificateIdAndIsDeleted(id, true).orElse(null);
/* 로그 메세지 작성 */
String description = "domain: " + certificate.getDomain() + "\n"
+ "email: " + certificate.getEmail() + "\n"
+ "challenge: " + certificate.getChallenge() + "\n"
+ "expiresAt: " + (certificate.getExpiresAt() != null ? certificate.getExpiresAt().format(LOG_DATE_FORMATTER) : "null");
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.CERTIFICATE)
.objectId(certificate.getCertificateId())
.action(Action.DELETE)
.projectId(certificate.getProjectId())
.description(description)
.build());
}
/* Update(edit) 로깅 */
@Around("execution(* com.aolda.itda.service.certificate.*Service.*edit*(..))")
public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 변경 전 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Certificate old = certificateRepository.findByCertificateIdAndIsDeleted(id, false).orElse(null);
if (old != null) {
entityManager.detach(old);
}
/* 메소드 진행 */
Object result = joinPoint.proceed();
/* 변경 후 엔티티 조회 */
Certificate newObj = certificateRepository.findByCertificateIdAndIsDeleted(id, false).orElse(null);
/* 로그 메세지 작성 */
String description = "domain: " + old.getDomain() + (old.getDomain().equals(newObj.getDomain()) ? "" : " -> " + newObj.getDomain()) + "\n"
+ "email: " + old.getEmail() + (old.getEmail().equals(newObj.getEmail()) ? "" : " -> " + newObj.getEmail()) + "\n"
+ "challenge: " + old.getChallenge() + (old.getChallenge() == newObj.getChallenge() ? "" : " -> " + newObj.getChallenge()) + "\n"
+ "expiresAt: " + (old.getExpiresAt() != null ? old.getExpiresAt().format(LOG_DATE_FORMATTER) : "null")
+ (old.getExpiresAt() != null && newObj.getExpiresAt() != null && !old.getExpiresAt().equals(newObj.getExpiresAt()) ? " -> " + newObj.getExpiresAt().format(LOG_DATE_FORMATTER) : "");
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.CERTIFICATE)
.objectId(newObj.getCertificateId())
.action(Action.UPDATE)
.projectId(newObj.getProjectId())
.description(description)
.build());
return result;
}
}
\ No newline at end of file
package com.aolda.itda.aspect;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.entity.forwarding.Forwarding;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.Log;
import com.aolda.itda.entity.log.ObjectType;
import com.aolda.itda.entity.user.User;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.certificate.CertificateRepository;
import com.aolda.itda.repository.forwarding.ForwardingRepository;
import com.aolda.itda.repository.log.LogRepository;
import com.aolda.itda.repository.routing.RoutingRepository;
import com.aolda.itda.repository.user.UserRepository;
import com.aolda.itda.service.AuthService;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
@RequiredArgsConstructor
public class ForwardingLogAspect {
private final ForwardingRepository forwardingRepository;
private final LogRepository logRepository;
private final EntityManager entityManager;
private final UserRepository userRepository;
/* Create 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*create*(..))"
, returning = "result")
public void createLogging(JoinPoint joinPoint, ForwardingDTO result) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 생성된 엔티티 조회 */
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(result.getId(), false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + forwarding.getName() + "\n"
+ "serverPort: " + forwarding.getServerPort() + "\n"
+ "instanceIp: " + forwarding.getInstanceIp() + "\n"
+ "instancePort: " + forwarding.getInstancePort();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(forwarding.getForwardingId())
.action(Action.CREATE)
.projectId(forwarding.getProjectId())
.description(description)
.build());
}
/* Delete 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*delete*(..))")
public void deleteLogging(JoinPoint joinPoint) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 삭제된 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(id, true).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + forwarding.getName() + "\n"
+ "serverPort: " + forwarding.getServerPort() + "\n"
+ "instanceIp: " + forwarding.getInstanceIp() + "\n"
+ "instancePort: " + forwarding.getInstancePort();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(forwarding.getForwardingId())
.action(Action.DELETE)
.projectId(forwarding.getProjectId())
.description(description)
.build());
}
/* Update(edit) 로깅 */
@Around("execution(* com.aolda.itda.service.forwarding.*Service.*edit*(..))")
public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 변경 전 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Forwarding old = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
if (old != null) {
entityManager.detach(old);
}
/* 메소드 진행 */
Object result = joinPoint.proceed();
/* 변경 후 엔티티 조회*/
Forwarding newObj = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : (" -> " + newObj.getName())) + "\n"
+ "serverPort: " + old.getServerPort() + (old.getServerPort().equals(newObj.getServerPort()) ? "" : (" -> " + newObj.getServerPort())) + "\n"
+ "instanceIp: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : (" -> " + newObj.getInstanceIp())) + "\n"
+ "instancePort: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : (" -> " + newObj.getInstancePort()));
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(newObj.getForwardingId())
.action(Action.UPDATE)
.projectId(newObj.getProjectId())
.description(description)
.build());
return result;
}
}
package com.aolda.itda.aspect;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.dto.routing.RoutingDTO;
import com.aolda.itda.entity.forwarding.Forwarding;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.Log;
import com.aolda.itda.entity.log.ObjectType;
import com.aolda.itda.entity.routing.Routing;
import com.aolda.itda.entity.user.User;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.forwarding.ForwardingRepository;
import com.aolda.itda.repository.log.LogRepository;
import com.aolda.itda.repository.routing.RoutingRepository;
import com.aolda.itda.repository.user.UserRepository;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
@RequiredArgsConstructor
public class RoutingLogAspect {
private final RoutingRepository routingRepository;
private final UserRepository userRepository;
private final LogRepository logRepository;
private final EntityManager entityManager;
/* Create 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*create*(..))"
, returning = "result")
public void createLogging(JoinPoint joinPoint, RoutingDTO result) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 생성된 엔티티 조회 */
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(result.getId(), false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + routing.getName() + "\n"
+ "domain: " + routing.getDomain() + "\n"
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(routing.getRoutingId())
.action(Action.CREATE)
.projectId(routing.getProjectId())
.description(description)
.build());
}
/* Delete 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*delete*(..))")
public void deleteLogging(JoinPoint joinPoint) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 삭제된 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(id, true).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + routing.getName() + "\n"
+ "domain: " + routing.getDomain() + "\n"
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(routing.getRoutingId())
.action(Action.DELETE)
.projectId(routing.getProjectId())
.description(description)
.build());
}
/* Update(edit) 로깅 */
@Around("execution(* com.aolda.itda.service.routing.*Service.*edit*(..))")
public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 변경 전 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Routing old = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
if (old != null) {
entityManager.detach(old);
}
/* 메소드 진행 */
Object result = joinPoint.proceed();
/* 변경 후 엔티티 조회 */
Routing newObj = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : " -> " + newObj.getName()) + "\n"
+ "domain: " + old.getDomain() + (old.getDomain().equals(newObj.getDomain()) ? "" : " -> " + newObj.getDomain()) + "\n"
+ "ip: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : " -> " + newObj.getInstanceIp()) + "\n"
+ "port: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : " -> " + newObj.getInstancePort()) + "\n";
if (isSameCertificate(old, newObj)) {
description = description + "certificateId: " + (old.getCertificate() == null ? "null" : old.getCertificate().getCertificateId()) + "\n";
} else {
description = description + "certificateId: " + (old.getCertificate() == null ? "null" : old.getCertificate().getCertificateId()) +
(newObj.getCertificate() == null ? "null" : " -> " + newObj.getCertificate().getCertificateId()) + "\n";
}
description = description + "caching: " + (old.getCaching() == newObj.getCaching() ? newObj.getCaching() : (" -> " + newObj.getCaching()));
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(newObj.getRoutingId())
.action(Action.UPDATE)
.projectId(newObj.getProjectId())
.description(description)
.build());
return result;
}
private boolean isSameCertificate(Routing old, Routing newObj) {
if (old.getCertificate() == null && newObj.getCertificate() == null) {
return true;
} else if (old.getCertificate() == null || newObj.getCertificate() == null) {
return false;
} else {
return old.getCertificate().getCertificateId().equals(newObj.getCertificate().getCertificateId());
}
}
}
package com.aolda.itda.config;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Component
@Slf4j
public class AuthFilter extends OncePerRequestFilter {
private final AuthService authService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getRequestURI().contains("/api/auth")) {
filterChain.doFilter(request, response);
return;
}
String token = request.getHeader("X-Subject-Token");
// 토큰 헤더 검증
if (token == null || token.isEmpty()) {
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
// 유효 토큰 검증
String userId = authService.validateTokenAndGetUserId(token);
if (userId == null) {
log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
// 프로젝트 권한 검증
String projectId = request.getParameter("projectId");
if (projectId != null) {
try {
authService.getBestRoleWithinProject(token, projectId).get("role");
if (!request.getMethod().equals("GET") && !authService.getBestRoleWithinProject(token, projectId).get("role").equals("admin")) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
} catch (Exception e) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
}
// 프로젝트 리스트 조회
List<String> projects;
if (authService.isAdmin(Map.of("id", userId, "token", token))) {
projects = authService.getAllProjects(token).stream().map(IdAndNameDTO::getId).toList();
} else {
projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token)).stream().map(IdAndNameDTO::getId).toList();
}
request.setAttribute("projects", projects);
request.setAttribute("user", Map.of("id", userId, "token", token));
filterChain.doFilter(request, response);
}
}
\ No newline at end of file
package com.aolda.itda.config;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.io.IOException;
import java.util.Map;
@Component
@RequiredArgsConstructor
public class LoggingFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
private final AuthService authService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Request Body를 읽을 수 있도록 래핑
ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
filterChain.doFilter(cachingRequest, response);
// 로그 기록
logRequest(cachingRequest);
}
private void logRequest(ContentCachingRequestWrapper request) throws JsonProcessingException {
String ip = request.getRemoteAddr();
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String body = getRequestBody(request);
Map<String, String> user = (Map<String, String>) request.getAttribute("user");
logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, User: {}, Request Body: {}",
ip, method, uri, (queryString != null ? queryString : "None"), (user != null ? user.get("id") : "None"),
(!body.isEmpty() ? body : "None"));
}
private String getRequestBody(ContentCachingRequestWrapper request) {
byte[] buf = request.getContentAsByteArray();
return (buf.length > 0) ? new String(buf) : "";
}
}
package com.aolda.itda.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AuthFilter authFilter;
private final LoggingFilter loggingFilter;
@Override
public void addCorsMappings(CorsRegistry registry) { // 스프링단에서 cors 설정
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "FETCH")
.allowedHeaders("*")
.allowCredentials(true)
.exposedHeaders("Authorization", "X-Refresh-Token", "Access-Control-Allow-Origin")
;
}
@Bean
public FilterRegistrationBean<AuthFilter> authFilterRegistration() {
FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(authFilter);
registrationBean.setOrder(1); // AuthFilter의 순서를 1로 설정
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() {
FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(loggingFilter);
registrationBean.setOrder(2); // LoggingFilter의 순서를 2로 설정
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
package com.aolda.itda.controller;
import com.aolda.itda.dto.auth.LoginRequestDTO;
import com.aolda.itda.service.AuthService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/login")
public ResponseEntity<Object> login(HttpServletResponse response,
@RequestBody LoginRequestDTO loginRequestDTO) throws JsonProcessingException {
return ResponseEntity.ok(authService.userLogin(response, loginRequestDTO));
}
@GetMapping("/role")
public ResponseEntity<Object> roleWithinProject(@RequestHeader("X-Subject-Token") String token,
@RequestParam String projectId) throws JsonProcessingException {
return ResponseEntity.ok(authService.getBestRoleWithinProject(token, projectId));
}
}
package com.aolda.itda.controller.certificate;
import com.aolda.itda.dto.PageResp;
import com.aolda.itda.dto.certificate.CertificateDTO;
import com.aolda.itda.service.certificate.CertificateService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class CertificateController {
private final CertificateService certificateService;
/**
* 인증서 생성
* POST /api/certificate?projectId=xxx
*/
@PostMapping("/certificate")
public ResponseEntity<Void> create(
@RequestParam String projectId,
@RequestBody CertificateDTO dto,
HttpServletRequest request
) {
certificateService.createCertificate(
projectId,
dto,
(List<String>) request.getAttribute("projects")
);
return ResponseEntity.ok().build();
}
/**
* 인증서 단건 조회
* GET /api/certificate?certificateId=xxx
*/
@GetMapping("/certificate")
public ResponseEntity<CertificateDTO> view(
@RequestParam Long certificateId,
HttpServletRequest request
) {
return ResponseEntity.ok(
certificateService.getCertificate(
certificateId,
(List<String>) request.getAttribute("projects")
)
);
}
/**
* 인증서 목록 조회 (domain 필터링 optional)
* GET /api/certificates?projectId=xxx&domain=foo
*/
@GetMapping("/certificates")
public ResponseEntity<PageResp<CertificateDTO>> lists(
@RequestParam String projectId,
@RequestParam(required = false) String domain,
@RequestParam(required = false) String query
) {
if (query != null) {
return ResponseEntity.ok(
certificateService.getCertificatesWithSearch(
projectId,
query
)
);
}
return ResponseEntity.ok(
certificateService.getCertificates(projectId, domain)
);
}
/**
* 인증서 수정
* PATCH /api/certificate?certificateId=xxx
*/
@PatchMapping("/certificate")
public ResponseEntity<Void> edit(
@RequestParam Long certificateId,
@RequestBody CertificateDTO dto,
HttpServletRequest request
) {
certificateService.editCertificate(
certificateId,
dto,
(List<String>) request.getAttribute("projects")
);
return ResponseEntity.ok().build();
}
/**
* 인증서 삭제
* DELETE /api/certificate?certificateId=xxx
*/
@DeleteMapping("/certificate")
public ResponseEntity<Void> delete(
@RequestParam Long certificateId,
HttpServletRequest request
) {
certificateService.deleteCertificate(
certificateId,
(List<String>) request.getAttribute("projects")
);
return ResponseEntity.ok().build();
}
}
package com.aolda.itda.controller.forwarding;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.service.forwarding.ForwardingService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ForwardingController {
private final ForwardingService forwardingService;
@PostMapping("/forwarding")
public ResponseEntity<Object> create(@RequestParam String projectId,
@RequestBody ForwardingDTO dto) {
forwardingService.createForwarding(projectId, dto);
return ResponseEntity.ok().build();
}
@GetMapping("/forwarding")
public ResponseEntity<Object> view(@RequestParam Long forwardingId, HttpServletRequest request) {
return ResponseEntity.ok(forwardingService.getForwarding(forwardingId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/forwardings")
public ResponseEntity<Object> lists(@RequestParam String projectId,
@RequestParam(required = false) String query) {
return ResponseEntity.ok(forwardingService.getForwardingsWithSearch(projectId, query));
}
@PatchMapping("/forwarding")
public ResponseEntity<Object> edit(@RequestParam Long forwardingId,
@RequestBody ForwardingDTO dto,
HttpServletRequest request) {
forwardingService.editForwarding(forwardingId, dto, (List<String>) request.getAttribute("projects") );
return ResponseEntity.ok().build();
}
@DeleteMapping("/forwarding")
public ResponseEntity<Object> delete(@RequestParam Long forwardingId,
HttpServletRequest request) {
forwardingService.deleteForwarding(forwardingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
}
package com.aolda.itda.controller.log;
import com.aolda.itda.service.log.LogService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class LogController {
private final LogService logService;
@GetMapping("/log")
public ResponseEntity<Object> view(@RequestParam Long logId, HttpServletRequest request) {
return ResponseEntity.ok(logService.getLog(logId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/logs")
public ResponseEntity<Object> lists(@RequestParam(required = false) String projectId
,@RequestParam(required = false) String type
,@RequestParam(required = false) String username
,@RequestParam(required = false) String action
,@RequestParam(defaultValue = "false") boolean isASC
,@PageableDefault(size = 10) Pageable pageable
,HttpServletRequest request) {
return ResponseEntity.ok(logService.getLogs(projectId, type, username, action, isASC, pageable,
(Map<String, String>) request.getAttribute("user")));
}
}
package com.aolda.itda.controller.main;
import com.aolda.itda.service.main.MainService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class MainController {
private final MainService mainService;
@GetMapping("/projects")
public ResponseEntity<Object> projects(HttpServletRequest request) throws JsonProcessingException {
return ResponseEntity.ok(mainService.getAllProjects((Map<String, String>) request.getSession().getAttribute("user")));
}
@GetMapping("/main")
public ResponseEntity<Object> mainInfo(@RequestParam String projectId, HttpServletRequest request) {
return ResponseEntity.ok(mainService.getMainInfo(projectId, (List<String>) request.getAttribute("projects")));
}
}
package com.aolda.itda.controller.routing;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.dto.routing.RoutingDTO;
import com.aolda.itda.service.routing.RoutingService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class RoutingController {
private final RoutingService routingService;
@PostMapping("/routing")
public ResponseEntity<Object> create(@RequestParam String projectId,
@RequestBody RoutingDTO dto) throws IOException {
routingService.createRouting(projectId, dto);
return ResponseEntity.ok().build();
}
@GetMapping("/routing")
public ResponseEntity<Object> view(@RequestParam Long routingId,
HttpServletRequest request) {
return ResponseEntity.ok(routingService.getRouting(routingId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/routings")
public ResponseEntity<Object> lists(@RequestParam String projectId,
@RequestParam(required = false) String query) {
return ResponseEntity.ok(routingService.getRoutingsWithSearch(projectId, query));
}
@PatchMapping("/routing")
public ResponseEntity<Object> edit(@RequestParam Long routingId,
@RequestBody RoutingDTO dto,
HttpServletRequest request) throws IOException {
routingService.editRouting(routingId, dto, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
@DeleteMapping("/routing")
public ResponseEntity<Object> delete(@RequestParam Long routingId,
HttpServletRequest request) {
routingService.deleteRouting(routingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
}
package com.aolda.itda.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PageResp<T> {
private Integer totalPages;
private Long totalElements;
private Integer size;
private List<T> contents;
private Boolean first;
private Boolean last;
public static <T> PageRespBuilder<T> builderFor(Class<T> clazz) {
return (PageRespBuilder<T>) new PageRespBuilder<>();
}
}
package com.aolda.itda.dto.auth;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.querydsl.core.annotations.QueryProjection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IdAndNameDTO {
private String id;
private String name;
@QueryProjection
public IdAndNameDTO(String id, String name) {
this.id = id;
this.name = name;
}
}
package com.aolda.itda.dto.auth;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class LoginRequestDTO {
private String id;
private String password;
}
package com.aolda.itda.dto.auth;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class LoginResponseDTO {
private Boolean isAdmin;
private List<IdAndNameDTO> projects;
}
package com.aolda.itda.dto.certificate;
import com.aolda.itda.entity.certificate.Challenge;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import lombok.*;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CertificateDTO {
private Long id; // 인증서 고유 ID
private String projectId; // 프로젝트 식별자
private String domain; // SSL 인증받을 도메인 주소
private String email;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")// 도메인 소유자의 이메일
private LocalDateTime expiresAt;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")// 인증서 만료일
private LocalDateTime createdAt;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")// 인증서 생성일
private LocalDateTime updatedAt; // 인증서 업데이트일
private Challenge challenge; // 챌린지 방식 (HTTP, DNS_CLOUDFLARE)
private Boolean isDeleted; // 삭제 여부 (soft delete)
private String apiToken;
}
/* 이메일, 챌린지 방식, http인지 dns인지... "*/
//도메인, 소유자 이메일, 챌린지 방식 확실하게 들어가야함!!
/*erd 보고 만들기*/
//Challenge 키는 따로 (private으로 api 키 받기)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment