feat: mens-admin 제거

xit-init 제거
      - mens-core에 merge
dev
gitea-관리자 12 months ago
parent f80c336e12
commit 149a206533

@ -1,38 +0,0 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

@ -1,174 +0,0 @@
### API 가이드
[카카오페이 문서발송 단건](./document/카카오페이내문서함_1.문서발송(단건).pdf)
[카카오페이 문서발송 대량](./document/카카오페이내문서함_1.문서발송(대량).pdf)
[카카오페이 문서발송 네트워크가이드](./document/카카오페이내문서함_1.네트워크가이드.pdf)
### swagger
[API URL](http://localhost:8081/swagger-ui.html)
[Front URL](http://localhost:8080/swagger-ui.html)
[Front test page](http://localhost:8080/api/kakaopay/test)
### API 결과 수신
* 정상 수신
```java
public class ApiResponseDTO<T> implements Serializable {
private static final String FAIL_STATUS = "fail";
private static final String ERROR_STATUS = "error";
@Schema(example = "true", description = "에러인 경우 false", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean success;
@Schema(example = " ", description = "HttpStatus.OK", requiredMode = Schema.RequiredMode.REQUIRED)
private String code;
@Schema(description = "결과 데이타, 오류시 null", example = " ")
private T data;
@Schema(description = "오류 발생시 오류 메세지", example = " ", requiredMode = Schema.RequiredMode.AUTO)
@Setter
private String message;
@Schema(example = " ", description = "HttpStatus.OK", requiredMode = Schema.RequiredMode.AUTO)
private HttpStatus httpStatus;
@Schema(description = "API 실행 결과 데이타 수")
private int count;
}
```
* 정상 수신
```json
{
"success": true,
"code": "200",
"httpStatus": "OK",
"message": "성공했습니다.",
"data": {
"token_status": "USED",
"token_expires_at": 1624344762,
"token_used_at": 0,
"doc_box_sent_at": 0,
"doc_box_received_at": 0,
"authenticated_at": 0,
"user_notified_at": 0,
"payload": "payload 파라미터 입니다.",
"signed_at": 0
},
"count": 1,
"paginationInfo": null
}
```
* 에러 수신
```json
{
"success": false,
"code": "error",
"data": null,
"message": "로그인 정보가 올바르지 않습니다.",
"httpStatus": "BAD_REQUEST",
"count": 0,
"paginationInfo": null
}
```
* API 호출 결과가 서버등(네트웍장애)의 장애인 경우를 제외 하고
예외로 return 되는 경우는 없다(발생시 공통팀에 반드시 알려 줄 것)
```js
$.ajax({
url: url,
type: method,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(data),
beforeSend: (xhr) => {
//xhr.setRequestHeader(header, token);
$("#loading").show();
},
success: function (res, textStatus) {
console.log( JSON.stringify(res));
if(res.success){
//정상 응답
$("#resData").text(res.data)
}else{
//에러 응답
$("#errData").text(JSON.stringify(res));
}
},
error : function(data) {
// 여기로 오는 경우 공통팀에 알려 주세요
alert("점검필요-error로 return", data.responseText);
},
complete: () => {
$("#loading").hide();
}
});
```
### API(Restful call) validation
* Controller 단에서 @Validated 사용으로 처리 가능
* But, 이경우 API 로그를 남기기 위해 Service 단에서 체크 하도록 컨트롤러 단에서는 유효성 체크 skip
### spring validation
```text
@Valid는 Java, @Validated는 Spring에서 지원하는 어노테이션
@Validated@Valid의 기능을 포함하고, 유효성을 검토할 그룹을 지정할 수 있는 기능이 추가됨
```
```java
@Null // null만 혀용
@NotNull // null을 허용하지 않습니다. "", " "는 허용
@NotEmpty // null, ""을 허용하지 않습니다. " "는 허용
@NotBlank // null, "", " " 모두 허용하지 않습니다.
@Email // 이메일 형식을 검사합니다. 다만 ""의 경우를 통과 시킵니다
@Pattern(regexp = ) // 정규식을 검사할 때 사용됩니다.
@Size(min=, max=) // 길이를 제한할 때 사용됩니다.
@Max(value = ) // value 이하의 값을 받을 때 사용됩니다.
@Min(value = ) // value 이상의 값을 받을 때 사용됩니다.
@Positive // 값을 양수로 제한합니다.
@PositiveOrZero // 값을 양수와 0만 가능하도록 제한합니다.
@Negative // 값을 음수로 제한합니다.
@NegativeOrZero // 값을 음수와 0만 가능하도록 제한합니다.
@Future // 현재보다 미래
@Past // 현재보다 과거
@AssertFalse // false 여부, null은 체크하지 않습니다.
@AssertTrue // true 여부, null은 체크하지 않습니다.
```
### intellij devtools 활성
```text
1. IntelliJ - Preferencs…
2. 컴파일러 - build project automatically(프로젝트 자동 빌드) 체크
3. Advanced Settings > Compiler
Allow auto-make to start even if developed application is current running
(개발된 애플리케이션이 현재 실행 중인 경우에도 auto-make가 시작되도록 허용) 체크
# 1 ~ 3항 까지 설정후 에도 안되는 경우만 4번 설정
4. 서버설정 : Edit Configurations...
Modfy Options > On Update Action > Update Resources
```
### ens-api 배포 및 run : profile에 따라 local|dev|prod
```shell
# jdk : azul-17.0.1
# 프로젝트 root 폴더로 이동 : ens-parent
# 패키지 생성 : local|dev|prod
$ mvnw clean package -P local
# 실행 : 프로젝트폴더/ens-parent/ens-api/target에 생성된 jar파일 실행
$ c:\tools\java\azul-17.0.1\java -jar -Dspring.profiles.active=local .\mens-api.jar
# mvn 명령어 설명
# -pl [모듈명] : 모듈명의 프로젝트만 빌드
# -am : 의존성 있는 프로젝트 함께 빌드 - C가 A를 디펜던시로 가지고 있으며 C를 빌드하면 A -> C 순으로 빌드
$ mvnw clean package -pl mens-api -am -P local
# -amd : 의존성 있는 타 프로젝트 빌드 - C가 A를 디펜던시로 가지고 있는 경우 A를 빌드 하면 A -> C 순으로 빌드
$ mvnw clean package -pl mens-core -amd -P local
mvn clean package -pl mens-batch -am -P prod
```
### 스프링 배치 DB schema
[mysql DDL 스크립트](./document/batch-schema-mysql.sql)

Binary file not shown.

@ -1,137 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>kr.xit</groupId>
<artifactId>mens-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>mens-admin</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<name>mens-admin</name>
<description>Mobile Electronic Administrator Web</description>
<dependencies>
<dependency>
<groupId>kr.xit</groupId>
<artifactId>mens-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
<scope>system</scope>
<systemPath>${basedir}/lib/ojdbc6.jar</systemPath>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${project.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*</include>
<include>static/**/*</include>
<include>egovframework/**/*</include>
<include>config/application.yml</include>
<include>config/application-app.yml</include>
<include>config/application-ens*</include>
<include>config/application-jpa.yml</include>
<include>config/application-${env}.yml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- dependency 추가 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- dependency jar 파일명 -->
<!--finalName>${project.name}-${project.version}</finalName-->
<!-- 기본생성 jar와 dependency jar 가 포함된 각각 파일 생성-->
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- spring-boot-maven-plugin : multi 프로젝트 이므로 mainClass 지정 필요 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<mainClass>kr.xit.EnsAdminApplication</mainClass>
<!-- 외부jar import -->
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -1,89 +0,0 @@
package kr.xit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import kr.xit.core.spring.config.support.CustomBeanNameGenerator;
import lombok.extern.slf4j.Slf4j;
/**
* <pre>
* description : ens API application main
* ServletComponentScan
* - 릿(, 릿, )
* - WebFilter, WebServlet, WebListener annotaion sacan
* - SpringBoot
* ConfigurationPropertiesScan
* - ConfigurationProperties annotaion class scan
* - EnableConfigurationProperties
* packageName : kr.xit
* fileName : EnsAdminApplication
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
*
* </pre>
*/
@Slf4j
@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = {"egovframework", "kr.xit"})
@ServletComponentScan
@ComponentScan(
nameGenerator = CustomBeanNameGenerator.class,
basePackages = {"egovframework", "kr.xit"}
)
public class EnsAdminApplication {
static final List<String> basePackages = new ArrayList<>(
Arrays.asList("egovframework", "kr.xit")
);
public static void main(String[] args) {
final String line = "====================================================================";
log.info(line);
log.info("==== EnsAdminApplication start :: active profiles - {} ====", System.getProperty("spring.profiles.active"));
if(Objects.isNull(System.getProperty("spring.profiles.active"))) {
log.error(">>>>>>>>>>>>>> Undefined start VM option <<<<<<<<<<<<<<");
log.error(">>>>>>>>>>>>>> -Dspring.profiles.active=local|dev|prd <<<<<<<<<<<<<<");
log.error("============== EnsAdminApplication start fail ===============");
log.error(line);
System.exit(-1);
}
log.info(line);
// beanName Generator 등록 : API v1, v2 등으로 분류하는 경우
// Bean 이름 식별시 풀패키지 명으로 식별 하도록 함
final CustomBeanNameGenerator beanNameGenerator = new CustomBeanNameGenerator();
beanNameGenerator.addBasePackages(basePackages);
final SpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(EnsAdminApplication.class);
applicationBuilder.beanNameGenerator(beanNameGenerator);
final SpringApplication application = applicationBuilder.build();
application.setBannerMode(Banner.Mode.OFF);
application.setLogStartupInfo(false);
//TODO : 이벤트 실행 시점이 Application context 실행 이전인 경우 리스너 추가
//PID(Process ID 작성)
application.addListeners(new ApplicationPidFileWriter()) ;
application.run(args);
log.info("=========================================================================================");
log.info("========== EnsAdminApplication load Complete :: active profiles - {} ==========", System.getProperty("spring.profiles.active"));
log.info("=========================================================================================");
}
}

@ -1,40 +0,0 @@
package kr.xit.biz.auth.service;
import egovframework.com.cmm.model.LoginVO;
import egovframework.com.cmm.util.EgovFileScrty;
import javax.annotation.Resource;
import kr.xit.core.spring.auth.mapper.IAuthMapper;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class AuthService extends EgovAbstractServiceImpl implements IAuthService {
@Resource
private IAuthMapper mapper;
/**
*
* @param vo LoginVO
* @return LoginVO
*/
@Override
public LoginVO actionLogin(LoginVO vo) {
// 1. 입력한 비밀번호를 암호화한다.
String enpassword = EgovFileScrty.encryptPassword(vo.getPassword(), vo.getId());
vo.setPassword(enpassword);
// 2. 아이디와 암호화된 비밀번호가 DB와 일치하는지 확인한다.
LoginVO loginVO = mapper.login(vo); //loginDAO.actionLogin(vo);
// 3. 결과를 리턴한다.
if (loginVO != null && !loginVO.getId().equals("") && !loginVO.getPassword().equals("")) {
return loginVO;
} else {
loginVO = new LoginVO();
}
return loginVO;
}
}

@ -1,32 +0,0 @@
package kr.xit.biz.auth.service;
import egovframework.com.cmm.model.LoginVO;
/**
*
* @author
* @since 2009.03.06
* @version 1.0
* @see
*
* <pre>
* << (Modification Information) >>
*
*
* ------- -------- ---------------------------
* 2009.03.06
* 2011.08.31 JJY 릿
*
* </pre>
*/
public interface IAuthService {
/**
*
*
* @param vo LoginVO
* @return LoginVO
*/
LoginVO actionLogin(LoginVO vo);
}

@ -1,208 +0,0 @@
package kr.xit.biz.auth.web;
import egovframework.com.cmm.model.LoginVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.xit.biz.auth.service.IAuthService;
import kr.xit.core.consts.Constants;
import kr.xit.core.consts.Constants.JwtToken;
import kr.xit.core.model.ApiResponseDTO;
import kr.xit.core.model.ClientInfoDTO;
import kr.xit.core.model.IApiResponse;
import kr.xit.core.model.TokenDTO;
import kr.xit.core.spring.auth.jwt.JwtTokenProvider;
import kr.xit.core.spring.util.MessageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
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.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.ModelAndView;
/**
* <pre>
* description :
*
* packageName : kr.xit.biz.auth
* fileName : AuthApiController
* author : limju
* date : 2023-04-26
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-26 limju
*
* </pre>
* @see
*/
@Tag(name = "AuthApiController", description = "인증 관리")
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/auth")
public class AuthController {
@Value("${app.token.saveType:header}")
private String authSaveType;
/** EgovLoginService */
private final IAuthService loginService;
/** EgovMessageSource */
private final MessageUtil messageUtil;
private final JwtTokenProvider jwtTokenProvider;
@Operation(summary = "로그인" , description = "로그인")
@GetMapping(value = "/loginForm")
public ModelAndView login() {
return new ModelAndView("/auth/loginForm.html");
}
/**
*
* @param loginVO , LoginVO
* @param request HttpServletRequest
* @return ()
*/
@io.swagger.v3.oas.annotations.parameters.RequestBody(
required = true,
content = {
@Content(
mediaType = "application/json",
examples = {
@ExampleObject(value = """
{
"id": "admin",
"password": "1",
"userSe": "USR"
}
""")
}
)
}
)
@Operation(summary = "로그인" , description = "로그인")
@PostMapping(value = "/login", consumes = {MediaType.APPLICATION_JSON_VALUE , MediaType.TEXT_HTML_VALUE})
public IApiResponse login(@RequestBody final LoginVO loginVO, HttpServletRequest request) {
// 1. 일반 로그인 처리
LoginVO loginResultVO = loginService.actionLogin(loginVO);
if (loginResultVO != null && loginResultVO.getId() != null && !loginResultVO.getId().equals("")) {
request.getSession().setAttribute(Constants.AuthSaveSession.LOGIN_VO.getCode(), loginResultVO);
return ApiResponseDTO.success(loginResultVO);
}
return ApiResponseDTO.success(messageUtil.getMessage("fail.common.login"));
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(
required = true,
content = {
@Content(
mediaType = "application/json",
examples = {
@ExampleObject(
name = "admin",
description = "admin",
value = """
{
"id": "admin",
"password": "1",
"userSe": "USR"
}
"""),
@ExampleObject(
name = "admin1",
description = "admin1",
value = """
{
"id": "admin1",
"password": "1",
"userSe": "USR"
}
""")
}
)
}
)
@Operation(summary = "로그인(JWT)" , description = "로그인(JWT)")
@PostMapping(value = "/loginJwt")
public IApiResponse loginJWT(@RequestBody final LoginVO loginVO, ClientInfoDTO clientInfo, final HttpServletRequest request, final HttpServletResponse response) {
HashMap<String, Object> resultMap = new HashMap<String, Object>();
// 1. 일반 로그인 처리
LoginVO loginResultVO = loginService.actionLogin(loginVO);
if (loginResultVO != null && loginResultVO.getId() != null && !loginResultVO.getId().equals("")) {
Map<String, Object> claimsMap = new HashMap<>();
// claimsMap.put("dkkdk", "kdkkdkdkd");
TokenDTO tokenDTO = jwtTokenProvider.generateTokenDto(claimsMap, String.format("{}{}",loginVO.getUserSe(), loginVO.getId()));
// String jwtToken = egovJwtTokenUtil.generateToken(loginVO.getId());
String username = jwtTokenProvider.getUsernameFromToken(tokenDTO.getAccessToken());
// System.out.println("Dec jwtToken username = "+username);
//서버사이드 권한 체크 통과를 위해 삽입
//EgovUserDetailsHelper.isAuthenticated() 가 그 역할 수행. DB에 정보가 없으면 403을 돌려 줌. 로그인으로 튕기는 건 프론트 쪽에서 처리
request.getSession().setAttribute(Constants.AuthSaveSession.LOGIN_VO.getCode(), loginResultVO);
// UsernamePasswordAuthenticationToken authenticationToken = jwtTokenProvider.toAuthentication(loginVO.getId(), loginVO.getPassword());
// Authentication authentication = authenticationManager.authenticate(authenticationToken);
//
//
// // Authentication 저장
// if(Objects.equals(authSaveType, Constants.AuthSaveType.SECURITY.getCode())){
// // TODO :: SessionCreationPolicy.STATELESS 인 경우 사용 불가
// SecurityContextHolder.getContext().setAuthentication(authentication);
//
// }else if(Objects.equals(authSaveType, Constants.AuthSaveType.SESSION.getCode())){
// session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
// }
//Map<String, Object> infoMap = new HashMap<>();
//infoMap.put(Constants.JwtToken.TOKEN_USER_ID.getCode(), loginVO.getId());
//infoMap.put(Constants.JwtToken.TOKEN_USER_MAIL.getCode(), loginVO.getEmail());
//String jwtToken = jwtTokenProvider.generateJwtAccessToken(authentication, infoMap);
//String jwtToken = jwtTokenProvider.generateJwtAccessToken(loginVO.getId(), "ROLE_USER");
resultMap.put("resultVO", loginResultVO);
resultMap.put("token", tokenDTO);
response.setHeader(JwtToken.HEADER_NAME.getCode(), String.format("%s %s", JwtToken.GRANT_TYPE.getCode(), tokenDTO.getAccessToken()));
return ApiResponseDTO.success(resultMap);
}
return ApiResponseDTO.error(messageUtil.getMessage("fail.common.login") );
}
/**
* .
* @return resultVO
* @exception Exception
*/
@Operation(summary = "logout" , description = "로그아웃")
@GetMapping(value = "/logout")
public IApiResponse actionLogoutJSON(HttpServletRequest request) {
RequestContextHolder.currentRequestAttributes().removeAttribute(Constants.AuthSaveSession.LOGIN_VO.getCode(), RequestAttributes.SCOPE_SESSION);
return ApiResponseDTO.empty();
}
}

@ -1,191 +0,0 @@
package kr.xit.core.aop;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.servlet.http.HttpServletRequest;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.support.utils.Checks;
import kr.xit.core.support.utils.JsonUtils;
import kr.xit.core.support.utils.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* <pre>
* description : logging trace aspect
* core LoggerAspect -> traceLogging / traceLoggingError / traceLoggingResult
*
* Logging trace
* - MDC(Mapped Diagnostic Context : logback, log4j )
* - ThreadLocal
* - nginx : proxy_set_header X-RequestID $request_id;
* - logback log pattern : [traceId=%X{request_id}]
*
* app.slack-webhook.enabled: true slack push
* Slack webhook : SlackWebhookPush
*
* packageName : kr.xit.core.aop
* fileName : TraceLoggerAspect
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
* 2023-06-12 julim RequestContextHolder.HttpServletRequest
* </pre>
* @see kr.xit.core.support.slack.SlackWebhookPush#sendSlackAlertLog(String, String, String)
*/
@Slf4j
@Aspect
@Component
public class TraceLoggerAspect {
@Value("${app.log.request.custom-enabled:false}")
private boolean isReqLogEnabled;
// 응답결과 로그
@Value("${app.log.response-enabled:false}")
private boolean isResLogEnabled;
@Pointcut("execution(public * egovframework..web.*.*(..)) || execution(public * kr.xit..web.*.*(..))")
public void requestPointCut() {
}
@Pointcut("execution(public * egovframework..*.*(..)) || execution(public * kr.xit..*.*(..))")
public void errorPointCut() {
}
@Pointcut("execution(public * egovframework..web.*.*(..)) || execution(public * kr.xit..web.*.*(..))")
public void resultPointCut() {
}
@Before(value = "requestPointCut()")
public void logBefore(JoinPoint joinPoint) {
if(!isReqLogEnabled) return;
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes != null? attributes.getRequest(): null;
assert request != null;
requestLog(request, getParams(request));
}
@AfterReturning(pointcut = "resultPointCut()", returning = "result")
public void logAfterReturning(final JoinPoint jp, final Object result) {
if(isResLogEnabled) {
log.info("{}{}{}",
"\n//============================= Http Response ==============================",
LogUtils.toString(result),
"\n=========================================================================//"
);
}
}
@AfterThrowing(value = "errorPointCut()", throwing="error")
public void afterThrowingProceed(final JoinPoint jp, final Throwable error) {
//traceApiLoggingError(jp, error);
}
private String getResult(final Object o){
//noinspection rawtypes
if(o instanceof Future future) {
try {
return JsonUtils.toJson(future.get());
} catch (InterruptedException ie){
// thread pool에 에러 상태 전송
Thread.currentThread().interrupt();
throw BizRuntimeException.create(ie);
} catch (ExecutionException ee) {
throw BizRuntimeException.create(ee);
}
}else{
return JsonUtils.toJson(o);
}
}
private void requestLog(HttpServletRequest request, JSONObject params) {
if (log.isDebugEnabled()) {
Map<String, Object> map = new LinkedHashMap<>();
//sb.append("Ajax Call : " + "XMLHttpRequest".equals(request.getHeader(Globals.AJAX_HEADER))).append("\n");
map.put("URI", request.getRequestURI());
map.put("URL", request.getRequestURL());
map.put("IP", request.getRemoteAddr());
map.put("Referer URI", request.getHeader("referer"));
map.put("Method", request.getMethod());
map.put("User Agent", request.getHeader("User-Agent"));
map.put("Session", request.getSession().getId());
map.put("Locale", request.getLocale().getCountry());
map.put("ContentType", request.getContentType());
map.put("Parameters", params);
log.info("{}{}{}",
"\n//============================= Http Request ==============================",
LogUtils.toString(map),
"\n=========================================================================//"
);
map.clear();
}
}
@SuppressWarnings("unchecked")
private JSONObject getParams(HttpServletRequest request) {
JSONObject jsonObject = new JSONObject();
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String param = params.nextElement();
String replaceParam = param.replaceAll("\\.", "-");
jsonObject.put(replaceParam, maskingParam(replaceParam, request.getParameter(param)));
}
return jsonObject;
}
private String maskingParam(final String key, final String value){
if(Checks.isEmpty(value)) return value;
if("juminId".equals(key)) {
if(value.length() == 14) {
return value.replaceAll("([0-9]{6})-([1-4]{1})([0-9]{6})", "$1-$2******");
}
return value.replaceAll("([0-9]{6})([1-4]{1})([0-9]{6})", "$1$2******");
}
if("telNo".equals(key)) {
if(value.contains("-")){
return value.replaceAll("-[0-9]{3,4}-", "-****-");
};
return value.replaceAll("([0-9]{3})([0-9]{4})([0-9]{4})", "$1$2****");
}
if("email".equals(key)) {
return value.replaceAll("[a-z,A-Z,0-9]+@", "******@");
}
if("name".equals(key)) {
return value.replaceAll("(?<=.{1}).", "*");
}
return value;
}
@SuppressWarnings("unchecked")
private String resetJsonMasking(final JSONObject json){
for (Object key : json.keySet()) {
if(Checks.isEmpty(json.get(key))) {
json.put(key, json.get(key));
}else {
json.put(key, maskingParam((String) key, String.valueOf(json.get(key))));
}
}
return json.toJSONString();
}
}

@ -1,38 +0,0 @@
package kr.xit.core.model;
import kr.xit.core.spring.config.WebServerConfig;
import kr.xit.core.spring.resolver.ClientInfoArgumentResolver;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
/**
* <pre>
* description : Client class
* set
* -> 1. HandlerMethodArgumentResolver ClientInfoDTO
* 2. WebMvcConfigurer Resolver
* 3. Controller .
* packageName : kr.xit.core.model
* fileName : ClientInfoDTO
* author : limju
* date : 2023-04-26
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-26 limju
*
* </pre>
* @see ClientInfoArgumentResolver
* @see WebServerConfig
*/
@Getter
@AllArgsConstructor
@ToString
@Builder
public class ClientInfoDTO {
private final String channel;
private final String clientAddress;
}

@ -1,46 +0,0 @@
package kr.xit.core.spring.auth;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.xit.core.model.ApiResponseDTO;
import kr.xit.core.support.utils.JsonUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
/**
* fileName : JwtAuthenticationEntryPoint
* author : crlee
* date : 2023/06/11
* description :
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2023/06/11 crlee
*/
//@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
// 403 에러
@SuppressWarnings("rawtypes")
ApiResponseDTO apiResponseDTO = ApiResponseDTO.builder()
.success(false)
.code(String.valueOf(HttpStatus.FORBIDDEN.value()))
.message("인가된 사용자가 아닙니다")
.build();
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType(MediaType.APPLICATION_JSON.toString());
response.setCharacterEncoding("UTF-8");
response.getWriter().println(JsonUtils.toJson(apiResponseDTO));
//TODO:: 페이지 생성후 처리
//response.sendRedirect("");
}
}

@ -1,48 +0,0 @@
package kr.xit.core.spring.auth;
import egovframework.com.cmm.model.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* fileName : CustomAuthenticationPrincipalResolver
* author : crlee
* date : 2023/07/13
* description :
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2023/07/13 crlee
*/
@Slf4j
public class CustomAuthenticationPrincipalResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(AuthenticationPrincipal.class) &&
parameter.getParameterType().equals(LoginVO.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null ||
authentication.getPrincipal() == null ||
"anonymousUser".equals(authentication.getPrincipal())
) {
log.info("익명(anonymousUser) 사용자 로그인 처리로 LoginVO 생성");
return new LoginVO();
}
log.info("사용자 로그인 {}", authentication.getPrincipal());
return authentication.getPrincipal();
}
}

@ -1,49 +0,0 @@
package kr.xit.core.spring.auth;
import java.util.List;
import kr.xit.core.exception.BizRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
/**
* <pre>
* description : utilis class
* packageName : kr.xit.core.spring.auth
* fileName : CustomAuthorityUtils
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Slf4j
public class CustomAuthorityUtils {
/**
* <pre>
* role List<GrantedAuthority>
* ROLE_USER, ROLE_ADMIN
* @param role : ROLE_USR|ROLE_ADMIN
* @return List<GrantedAuthority> </pre>
*/
public static List<GrantedAuthority> createAuthorities(String role) {
return List.of(new SimpleGrantedAuthority("ROLE_" + role));
}
/**
* role
* @param role String USER|ADMIN
*/
public static void verifiedRole(String role) {
if (role == null) {
throw BizRuntimeException.create("fail.jwt.role.notExists");
} else if (!role.equals("USER") && !role.equals("ADMIN")) {
throw BizRuntimeException.create("fail.jwt.role.invalid", new String[]{role});
}
}
}

@ -1,116 +0,0 @@
package kr.xit.core.spring.auth;
import egovframework.com.cmm.model.LoginVO;
import java.util.Collection;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
/**
* <pre>
* description : UserDetails
* Spring Security User
* packageName : kr.xit.core.spring.auth
* fileName : CustomUserDetails
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Getter
@NoArgsConstructor
@ToString
public class CustomUserDetails implements UserDetails {
private String id;
private String email;
private String role;
private String password;
private CustomUserDetails(LoginVO loginVO) {
this.id = loginVO.getId();
this.email = loginVO.getEmail();
this.password = loginVO.getPassword();
//this.role = loginVO.getRole();
}
private CustomUserDetails(String email, String role) {
this.email = email;
this.role = role;
}
private CustomUserDetails(String email, String password, String role) {
this.email = email;
this.password = password;
this.role = role;
}
public static CustomUserDetails of(LoginVO loginVO) {
return new CustomUserDetails(loginVO);
}
public static CustomUserDetails of(String email, String role) {
return new CustomUserDetails(email, role);
}
public static CustomUserDetails of(String email, String password, String role) {
return new CustomUserDetails(email, password, role);
}
/**
* <pre>
* List<GrantedAuthority>
* @return Collection<? extends GrantedAuthority>
* </pre>
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return CustomAuthorityUtils.createAuthorities(role);
}
@Override
public String getUsername() {
return this.id;
}
/**
* ?
* @return true|false
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* ?
* @return true| false
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* ?
* @return true| flase
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* ?
* @return true|false
*/
@Override
public boolean isEnabled() {
return true;
}
}

@ -1,158 +0,0 @@
package kr.xit.core.spring.auth;
import java.util.List;
import kr.xit.core.spring.auth.filter.JwtAuthenticationFilter;
import kr.xit.core.spring.auth.handler.CustomAccessDeniedHandler;
import kr.xit.core.spring.auth.handler.CustomAuthenticationFailureHandler;
import kr.xit.core.spring.auth.handler.CustomAuthenticationSuccessHandler;
import kr.xit.core.spring.auth.jwt.JwtTokenProvider;
import kr.xit.core.spring.auth.mapper.IAuthMapper;
import kr.xit.core.spring.util.AES128Config;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* <pre>
* description : Spring security
* packageName : kr.xit.core.spring.auth
* fileName : SecurityConfig
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Slf4j
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig implements WebMvcConfigurer {
//Http Methpd : Get 인증예외 List
private String[] AUTH_GET_WHITELIST = {
"/schedule/daily", //일별 일정 조회
"/schedule/week", //주간 일정 조회
"/schedule/{schdulId}", //일정 상세조회
};
// 인증 예외 List
@Value("${app.spring.security.white-list}")
private String[] AUTH_WHITELIST;
private final JwtTokenProvider jwtTokenProvider;
private final AES128Config aes128Config;
private final IAuthMapper authMapper;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new CustomAuthenticationPrincipalResolver());
}
/**
* <pre>
* SecurityFilterChain
* ->
* <code>headers().frameOptions().sameOrigin()</code> : X-Frame-Options SAMEORIGIN , iframe
* <code>http.csrf().disable()</code> : jwt CSRF(Cross-Site Request Forgery) .
* <code>http.cors().configurationSource(corsConfigurationSource())</code> : CORS(Cross-Origin Resource Sharing) -
* <code>http.formLogin().disable()</code> :
* <code>http.httpBasic().disable()</code> : HTTP
* <code>sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)</code> :
* <code>exceptionHandling()</code> :
* <code>authenticationEntryPoint(new CustomAuthenticationEntryPoint())</code> :
* <code>accessDeniedHandler(new CustomAccessDeniedHandler())</code> :
* <code>apply(new CustomFilterConfigurer())</code> :
* <code>authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())</code> : HTTP
* @param http HttpSecurity
* @return SecurityFilterChain
* </pre>
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.headers().frameOptions().sameOrigin()
.and()
.csrf().disable()
//.cors().configurationSource(corsConfigurationSource())
.cors().and()
//.formLogin().disable()
//.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
// .authenticationEntryPoint(
// (request, response, authException) -> response.sendRedirect(""))
// .accessDeniedHandler(
// (request, response, accessDeniedException) -> response.sendRedirect(""))
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.accessDeniedHandler(new CustomAccessDeniedHandler())
.and()
.apply(new CustomFilterConfigurer(authMapper))
.and()
// TODO: 추후 권한 별 페이지 접근제어 설정 예정
.authorizeHttpRequests(authorize -> authorize
.antMatchers(AUTH_WHITELIST).permitAll()
//.antMatchers(AUTH_WHITELIST).authenticated()
.antMatchers(HttpMethod.GET,AUTH_GET_WHITELIST).permitAll()
.anyRequest().authenticated()
);
return http.build();
}
/**
* <pre>
* description : HttpSecurity
* ->
* - AbstractHttpConfigurer configure()
* packageName : kr.xit.core.spring.auth
* fileName : CustomFilterConfigurer
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@RequiredArgsConstructor
public class CustomFilterConfigurer extends
AbstractHttpConfigurer<CustomFilterConfigurer, HttpSecurity> {
private final IAuthMapper authMapper;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
log.info("SecurityConfiguration.CustomFilterConfigurer.configure excute");
AuthenticationManager authenticationManager = httpSecurity.getSharedObject(
AuthenticationManager.class);
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager,
jwtTokenProvider, aes128Config, authMapper);
//JwtVerificationFilter jwtVerificationFilter = new JwtVerificationFilter(jwtTokenProvider, redisService);
jwtAuthenticationFilter.setFilterProcessesUrl("/auth/login");
jwtAuthenticationFilter.setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler());
jwtAuthenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
httpSecurity
.addFilter(jwtAuthenticationFilter)
// .addFilterAfter(jwtVerificationFilter, JwtAuthenticationFilter.class);
// .addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
;
}
}
}

@ -1,103 +0,0 @@
package kr.xit.core.spring.auth.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import egovframework.com.cmm.model.LoginVO;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.model.RefreshTokenDTO;
import kr.xit.core.model.TokenDTO;
import kr.xit.core.spring.auth.CustomUserDetails;
import kr.xit.core.spring.auth.jwt.JwtTokenProvider;
import kr.xit.core.spring.auth.mapper.IAuthMapper;
import kr.xit.core.spring.util.AES128Config;
import kr.xit.core.support.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* <pre>
* description : /
* UsernamePasswordAuthenticationFilter
* 1. .
* -> successfulAuthentication/unSuccessfulAuthentication
* 2. /login
* -> Url setFilterProcessesUrl() Url
* 3. Jwt .
* packageName : kr.xit.core.spring.auth.filter
* fileName : JwtAuthorizationFilter
* author : julim
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 julim
*
* </pre>
*/
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
private final AES128Config aes128Config;
private final IAuthMapper authMapper;
@SneakyThrows
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// ServletInputStream을 LoginDto 객체로 역직렬화
ObjectMapper objectMapper = new ObjectMapper();
LoginVO loginVO = objectMapper.readValue(request.getInputStream(), LoginVO.class);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginVO.getEmail(), loginVO.getPassword());
return authenticationManager.authenticate(authenticationToken);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
Map<String,Object> cliams = new HashMap<>();
cliams.put("role", customUserDetails.getRole());
TokenDTO tokenDto = jwtTokenProvider.generateTokenDto(cliams, customUserDetails.getUsername());
String accessToken = tokenDto.getAccessToken();
String refreshToken = tokenDto.getRefreshToken();
String encryptedRefreshToken = aes128Config.encryptAes(refreshToken);
jwtTokenProvider.accessTokenSetHeader(accessToken, response);
jwtTokenProvider.refresshTokenSetHeader(encryptedRefreshToken, response);
LoginVO loginVO = authMapper.selectUserById(customUserDetails.getId())
.orElseThrow(() -> BizRuntimeException.of("fail.auth.login.user"));
//TODO:: 로그인 성공시 Refresh Token 저장
Date date = jwtTokenProvider.getExpirationDateFromToken(refreshToken);
authMapper.saveRefreshToken(
RefreshTokenDTO.builder()
.id(loginVO.getId())
.refreshToken(refreshToken)
.refreshTokenExpiresIn(DateUtils.parseToLong(date))
.build()
);
//...(loginVO.getId(), refreshToken, Duration.ofMillis(DateUtils.parseToLong(date)));
this.getSuccessHandler().onAuthenticationSuccess(request, response, authentication);
}
}

@ -1,24 +0,0 @@
package kr.xit.core.spring.auth.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private String denied_url;
public CustomAccessDeniedHandler() {
this.denied_url = "egovframework/com/cmm/error/csrfAccessDenied";
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect(request.getContextPath() + denied_url);
}
}

@ -1,32 +0,0 @@
package kr.xit.core.spring.auth.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException, IOException {
String errorMessage = "Invalid Username or Password";
if(exception instanceof BadCredentialsException){
errorMessage = "Invalid Username or Password";
}else if(exception instanceof InsufficientAuthenticationException){
errorMessage = "Invalid Secret Key";
}
setDefaultFailureUrl("/auth/login?error=true&exception=" + exception.getMessage());
super.onAuthenticationFailure(request, response, exception);
}
}

@ -1,36 +0,0 @@
package kr.xit.core.spring.auth.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final RequestCache requestCache = new HttpSessionRequestCache();
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
setDefaultTargetUrl("/auth/login");
SavedRequest savedRequest = requestCache.getRequest(request, response);
// 사용자가 권한이 필요한 자원에 접근해 인증 예외가 발생해 인증을 처리하는 것이 아닌 경우
// SavedRequest 객체가 생성되지 않는다.
if (savedRequest != null) {
String targetUrl = savedRequest.getRedirectUrl();
redirectStrategy.sendRedirect(request, response, targetUrl);
} else {
redirectStrategy.sendRedirect(request, response, getDefaultTargetUrl());
}
super.clearAuthenticationAttributes(request);
}
}

@ -1,29 +0,0 @@
package kr.xit.core.spring.auth.mapper;
import egovframework.com.cmm.model.LoginVO;
import java.util.Optional;
import kr.xit.core.model.RefreshTokenDTO;
import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
/**
* <pre>
* description :
*
* packageName : kr.xit.core.spring.auth.mapper
* fileName : IAuthMapper
* author : limju
* date : 2023-11-29
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-11-29 limju
*
* </pre>
*/
@Mapper
public interface IAuthMapper {
<T> LoginVO login(T t);
Optional<LoginVO> selectUserById(String id);
int saveRefreshToken(final RefreshTokenDTO dto);
}

@ -1,32 +0,0 @@
package kr.xit.core.spring.auth.service;
import egovframework.com.cmm.model.LoginVO;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.spring.auth.CustomUserDetails;
import kr.xit.core.spring.auth.mapper.IAuthMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final IAuthMapper mapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return mapper.selectUserById(username)
.map(this::createUserDetails)
.orElseThrow(() -> BizRuntimeException.of("fail.auth.login.user"));
}
private UserDetails createUserDetails(LoginVO member) {
return CustomUserDetails.of(member);
}
}

@ -1,35 +0,0 @@
package kr.xit.core.spring.config;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* <pre>
* description : Springdoc(swagger)
*
* packageName : kr.xit.core.spring.config
* fileName : SpringDocsConfig
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
*
* </pre>
*/
@ConditionalOnProperty(value = "springdoc.swagger-ui.enabled", havingValue = "true", matchIfMissing = false)
@Configuration
public class SpringDocsApiConfig {
@Bean
public GroupedOpenApi authentification() {
return GroupedOpenApi.builder()
.group("1. Authentification API")
.pathsToMatch(
"/auth/**"
)
.build();
}
}

@ -1,32 +0,0 @@
package kr.xit.core.spring.config;
import java.util.List;
import kr.xit.core.model.ClientInfoDTO;
import kr.xit.core.spring.resolver.ClientInfoArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* <pre>
* description : Web server
* packageName : kr.xit.core.spring.config
* fileName : WebServerConfig
* author : limju
* date : 2023-04-26
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-26 limju
*
* </pre>
* @see ClientInfoDTO
* @see WebServerConfig
*/
@Configuration
public class WebServerConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new ClientInfoArgumentResolver());
}
}

@ -1,50 +0,0 @@
package kr.xit.core.spring.resolver;
import kr.xit.core.model.ClientInfoDTO;
import kr.xit.core.spring.config.WebServerConfig;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* <pre>
* description : Client ClientInfoDTO
* HandlerMethodArgumentResolver ClientInfoDTO
* -> WebMvcConfigurer Resolver
* packageName : kr.xit.core.spring.resolver
* fileName : ClientInfoArgumentResolver
* author : limju
* date : 2023-04-26
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-26 limju
*
* </pre>
* @see ClientInfoDTO
* @see WebServerConfig
*/
public class ClientInfoArgumentResolver implements HandlerMethodArgumentResolver {
private static final String HEADER_CHANNEL = "X-APP-CHANNEL";
private static final String HEADER_CLIENT_IP = "X-FORWORD-FOR";
@Override
public boolean supportsParameter(MethodParameter parameter) {
return ClientInfoDTO.class.equals(parameter.getParameterType());
}
@Override
public Object resolveArgument(@Nullable MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
String channel = webRequest.getHeader(HEADER_CHANNEL);
String clientAddress = webRequest.getHeader(HEADER_CLIENT_IP);
return new ClientInfoDTO(channel, clientAddress);
}
}

@ -1,47 +0,0 @@
package kr.xit.core.spring.util;
import kr.xit.core.spring.config.support.ApplicationContextProvider;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.ApplicationContext;
/**
* <pre>
* description : Get Bean Object
* Filter / Interceptor Bean
* (Bean @Autowired / @Resource )
* packageName : kr.xit.core.spring.util
* fileName : AdminSpringUtils
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
*
* </pre>
* @see ApplicationContextProvider
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AdminSpringUtils {
public static ApplicationContext getApplicationContext() {
return ApplicationContextProvider.getApplicationContext();
}
public static boolean containsBean(String beanName) {
return getApplicationContext().containsBean(beanName);
}
public static Object getBean(String beanName) {
return getApplicationContext().getBean(beanName);
}
public static Object getBean(Class<?> clazz) {
return getApplicationContext().getBean(clazz);
}
// public static ICmmEnsCacheService getCmmEnsCacheService(){
// return (ICmmEnsCacheService)getBean(CmmEnsCacheService.class);
// }
}

@ -1,29 +0,0 @@
#-----------------------------------------------------------------------
# application 설정
#-----------------------------------------------------------------------
app:
#---------------------------------------------------------------
# log 설정
# request:
# custom-enabled | common-enabled | filter-enabled 중 1개만 활성화
# --> 운영: common-enabled, 개발: custom-enabled 사용 권장
# response-enabled : 호출 결과 출력 - 운영시 false
# mdc : api 호출(서비스) 로그 기록
# uris : api 호출 로그 제외 패턴
#---------------------------------------------------------------
log:
request:
# exclude pattern : CommonsRequestLoggingFilter && LoggingFilter 적용
exclude-patterns: '/swagger-ui/(.*), /api-docs/(.*), /favicon.ico'
custom-enabled: false
# CommonsRequestLoggingFilter 사용 parameter 로그 출력
common-enabled: false
# Filter를 사용한 로그 출력
filter-enabled: false
response-enabled: false
# slack
slack-webhook:
enabled: false
url: https://hooks.slack.com/services/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

@ -1,82 +0,0 @@
#-----------------------------------------------------------------------
# dev 설정
#-----------------------------------------------------------------------
spring:
datasource:
hikari:
# 9 server
primary:
database: mysql
driver-class-name: org.mariadb.jdbc.Driver
jdbc-url: jdbc:mariadb://211.119.124.9:4407/mens?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true
username: root
password: xit1807
read-only: false
# multi-database
#secondary:
devtools:
livereload:
enabled: true
springdoc:
api-docs:
enabled: true
swagger-ui:
enabled: true
logging:
level:
root: debug
org.apache.http: warn
io.netty: warn
reactor.netty: WARN
# webclient logging
reactor.netty.http.client: DEBUG
#org.springframework.web.reactive.function.client.ExchangeFunctions: TRACE
org.springframework: warn
org.hibernate.validator.internal: WARN
file:
# 로그파일 위치
path: ${app.data.root.path}/mens/logs
name: ${app.name}
# ==================================================================================================================
# SQL logging lib setting
# ==================================================================================================================
decorator:
datasource:
p6spy:
enable-logging: true
app:
api-ip: 211.119.124.9
# 강제로 swagger-url을 지정해야 하는 경우만 선언
#swagger-url: 'http://localhost:${server.port}${server.servlet.context-path:}/'
# Spring Security cors 설정 :: CorsConfiguration 설정 값
cors:
allowed-origins: http://localhost:8080, http://${app.api-ip}:8080, http://localhost:8082, http://${app.api-ip}:8082
data:
root:
path: /data
#---------------------------------------------------------------
# log 설정
# request:
# custom-enabled | common-enabled | filter-enabled 중 1개만 활성화
# --> 운영: common-enabled, 개발: custom-enabled 사용 권장
# response-enabled : 호출 결과 출력 - 운영시 false
# mdc : api 호출(서비스) 로그 기록
# uris : api 호출 로그 제외 패턴
#---------------------------------------------------------------
log:
request:
custom-enabled: true
response-enabled: true
# slack
slack-webhook:
enabled: false
url: https://hooks.slack.com/services/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

@ -1,93 +0,0 @@
#-----------------------------------------------------------------------
# local 설정
#-----------------------------------------------------------------------
server:
port: 8444
http: 8080
spring:
datasource:
hikari:
# 9 server
primary:
database: mysql
driver-class-name: org.mariadb.jdbc.Driver
jdbc-url: jdbc:mariadb://211.119.124.9:4407/mens?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true
username: root
password: xit1807
read-only: false
# multi-database
#secondary:
devtools:
restart:
enabled: true
additional-exclude: static/**,public/**
livereload:
enabled: true
springdoc:
api-docs:
enabled: true
swagger-ui:
enabled: true
logging:
level:
root: debug
org.apache.http: warn
io.netty: warn
reactor.netty: WARN
# webclient logging
reactor.netty.http.client: DEBUG
#org.springframework.web.reactive.function.client.ExchangeFunctions: TRACE
org.springframework: warn
org.hibernate.validator.internal: WARN
file:
# 로그파일 위치
path: ${app.data.root.path}/mens/logs
name: ${app.name}
# ==================================================================================================================
# SQL logging lib setting
# ==================================================================================================================
decorator:
datasource:
p6spy:
enable-logging: true
app:
api-ip: 211.119.124.73
# 강제로 swagger-url을 지정해야 하는 경우만 선언
#swagger-url: 'http://localhost:${server.port}${server.servlet.context-path:}/'
# Spring Security cors 설정 :: CorsConfiguration 설정 값
cors:
allowed-origins:
http://localhost:${server.http},
http://${app.api-ip}:${server.http},
https://localhost:${server.port},
https://${app.api-ip}:${server.port}
data:
root:
#path: /Users/minuk/data
path: d:/data
#---------------------------------------------------------------
# log 설정
# request:
# custom-enabled | common-enabled | filter-enabled 중 1개만 활성화
# --> 운영: common-enabled, 개발: custom-enabled 사용 권장
# response-enabled : 호출 결과 출력 - 운영시 false
# mdc : api 호출(서비스) 로그 기록
# uris : api 호출 로그 제외 패턴
#---------------------------------------------------------------
log:
request:
custom-enabled: true
response-enabled: true
# slack
slack-webhook:
enabled: false
url: https://hooks.slack.com/services/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

@ -1,82 +0,0 @@
#-----------------------------------------------------------------------
# prod 설정
#-----------------------------------------------------------------------
spring:
datasource:
hikari:
# 9 server
primary:
database: mysql
driver-class-name: org.mariadb.jdbc.Driver
# jdbc:mariadb://127.0.0.1:4407/mens?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true
jdbc-url: ENC(N7TRplIpBBUbXtSi8fx0wr92OdMgvp9Iw5tmaW7EUaH6ialiAWohx+rOEZx/j+OHFkJSrhYQElPIVe5r4d0tWDNREpgvKwxZRTGXhNdTMMUUHonkGKfB7bURxMfjuMSQEUdKicPZv+xB9eGlwcuPpgC7vaQuZM6WrUDP31+6qYboTUQKBK/7lg==)
username: ENC(wgnjrc4VB7R3I+OwMV+iXQ==)
password: ENC(+sXCmhmSV3Q/3KgOnmpnTQ==)
read-only: false
# multi-database
#secondary:
devtools:
livereload:
enabled: false
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
logging:
level:
root: warn
org.apache.http: warn
io.netty: warn
reactor.netty: WARN
# webclient logging
reactor.netty.http.client: warn
#org.springframework.web.reactive.function.client.ExchangeFunctions: TRACE
org.springframework: warn
org.hibernate.validator.internal: WARN
file:
# 로그파일 위치
path: ${app.data.root.path}/mens/logs
name: ${app.name}
# ==================================================================================================================
# SQL logging lib setting
# ==================================================================================================================
decorator:
datasource:
p6spy:
enable-logging: true
app:
api-ip: 103.145.215.46
# 강제로 swagger-url을 지정해야 하는 경우만 선언
swagger-url: 'http://103.145.215.46:8081/${server.servlet.context-path:}/'
# Spring Security cors 설정 :: CorsConfiguration 설정 값
cors:
allowed-origins: http://localhost, http://${app.api-ip}, http://localhost:8082, http://${app.api-ip}:8082, https://ens.sisul.or.kr
data:
root:
path: /data
#---------------------------------------------------------------
# log 설정
# request:
# custom-enabled | common-enabled | filter-enabled 중 1개만 활성화
# --> 운영: common-enabled, 개발: custom-enabled 사용 권장
# response-enabled : 호출 결과 출력 - 운영시 false
# mdc : api 호출(서비스) 로그 기록
# uris : api 호출 로그 제외 패턴
#---------------------------------------------------------------
log:
request:
common-enabled: true
response-enabled: false
# slack
slack-webhook:
enabled: false
url: https://hooks.slack.com/services/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

@ -1,110 +0,0 @@
#-----------------------------------------------------------------------
#
# egovframework 설정
# api 공통 설정
#-----------------------------------------------------------------------
Globals:
# DB서버 타입(hsql,mysql,oracle,altibase,tibero) - datasource 및 sqlMap 파일 지정에 사용됨
DbType: mysql
# MainPage Setting
MainPage: /cmm/main/mainPage.do
#server.servlet.context-path=/sht_boot_web
server:
port: 8080
error:
whitelabel:
enabled: false
app:
name: mens-admin
# springdoc url 정보
desc: 모바일 전자고지 Administrator
# spring security ignore
spring:
security:
white-list:
favicon.ico,
/,
/semantic/**
/auth/loginForm*,
/auth/login*,
/auth/loginJwt*,
/api-docs/**,
/swagger-resources,
/swagger-ui.html,
/swagger-ui/**
data:
root:
path: /data
file:
cmm:
temp-path: ${app.data.root.path}/temp
upload:
root: ${app.data.root.path}
# root: /data
# E-GREEN 우편 발송
post: /post/rcv/
spring:
main:
# 순환참조 에러 무시
allow-circular-references: true
pid:
file: ${app.data.root.path}/${app.name}.pid
profiles:
active: '@springProfilesActive@'
# core의 application-common.yml과 application-auth.yml include
include:
- https
- common
- auth
- app
# mvc:
# static-path-pattern: /resources/static/**
# view:
# prefix:
# suffix: .html
batch:
jdbc:
initialize-schema: NEVER #NEVER|ALWAYS
# JPA does not support custom isolation levels, so locks may not be taken when launching Jobs.
# To silence this warning, set 'spring.batch.jdbc.isolation-level-for-create' to 'default'.
isolation-level-for-create: default
job:
enabled: false
#-----------------------------------------------------------------
# xit framework 설정
#-----------------------------------------------------------------
datasource:
#type: com.zaxxer.hikari.HikariDataSource
hikari:
primary:
pool-name: xit-maria-pool
auto-commit: false
# 인프라의 적용된 connection time limit보다 작아야함
max-lifetime: 1800000
maximum-pool-size: 15
minimum-idle: 5
#transaction-isolation: TRANSACTION_READ_UNCOMMITTED
data-source-properties:
rewriteBatchedStatements: true
# secondary:
# pool-name: xit-oracle-pool
# auto-commit: false
# # 인프라의 적용된 connection time limit보다 작아야함
# max-lifetime: 1800000
# maximum-pool-size: 15
# minimum-idle: 5
## transaction-isolation: TRANSACTION_READ_UNCOMMITTED
# data-source-properties:
# rewriteBatchedStatements: true
logging:
level:
root: error

@ -1,382 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the Google coding conventions from Google Java Style
that can be found at https://google.github.io/styleguide/javaguide.html
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.org (or in your downloaded distribution).
To completely disable a check, just comment it out or delete it from the file.
To suppress certain violations please review suppression filters.
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
-->
<module name="Checker">
<module name="SuppressWarningsFilter"/>
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Excludes all 'module-info.java' files -->
<!-- See https://checkstyle.org/filefilters/index.html -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- https://checkstyle.org/filters/suppressionfilter.html -->
<module name="SuppressionFilter">
<property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
default="checkstyle-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.org/checks/whitespace/index.html -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="TreeWalker">
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="AvoidStarImport"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap">
<property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
</module>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NeedBraces">
<property name="tokens"
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
</module>
<module name="LeftCurly">
<property name="tokens"
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
COMPACT_CTOR_DEF, LITERAL_SWITCH"/>
</module>
<module name="SuppressionXpathSingleFilter">
<!-- suppresion is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
<property name="id" value="RightCurlyAlone"/>
<property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]
or preceding-sibling::*[last()][self::LCURLY]]"/>
</module>
<module name="WhitespaceAfter">
<property name="tokens"
value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE, LITERAL_RETURN,
LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, LITERAL_FINALLY, DO_WHILE, ELLIPSIS,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_CATCH, LAMBDA,
LITERAL_YIELD, LITERAL_CASE"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyLambdas" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<property name="ignoreEnhancedForColon" value="false"/>
<property name="tokens"
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="tokens"
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
COMPACT_CTOR_DEF"/>
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/259 -->
<property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/258 -->
<property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
ANNOTATION_DEF, RECORD_DEF"/>
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LambdaParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="PatternVariableName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="RecordComponentName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Record component name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="RecordTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Record type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="4"/>
<property name="braceAdjustment" value="4"/>
<property name="caseIndent" value="4"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="4"/>
<property name="arrayInitIndent" value="4"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="0"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
RECORD_COMPONENT_DEF"/>
</module>
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
<property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
</module>
<module name="MethodParamPad">
<property name="tokens"
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,
SUPER_CTOR_CALL, ENUM_CONSTANT_DEF, RECORD_DEF"/>
</module>
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT,
LABELED_STAT, METHOD_REF"/>
<property name="allowLineBreaks" value="true"/>
</module>
<module name="ParenPad">
<property name="tokens"
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
RECORD_DEF"/>
</module>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF,
TYPE_EXTENSION_AND "/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,
RECORD_DEF, COMPACT_CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="InvalidJavadocPosition"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph"/>
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod">
<property name="accessModifiers" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
</module>
<module name="MissingJavadocMethod">
<property name="scope" value="public"/>
<property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
COMPACT_CTOR_DEF"/>
</module>
<module name="MissingJavadocType">
<property name="scope" value="protected"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
RECORD_DEF, ANNOTATION_DEF"/>
<property name="excludeScope" value="nothing"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9]\w*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc"/>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation">
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
</module>
<!-- https://checkstyle.org/filters/suppressionxpathfilter.html -->
<module name="SuppressionXpathFilter">
<property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
default="checkstyle-xpath-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<module name="SuppressWarningsHolder" />
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)" />
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)" />
<property name="checkFormat" value="$1" />
</module>
<module name="SuppressWithNearbyCommentFilter">
<property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/>
<!-- $1 refers to the first match group in the regex defined in commentFormat -->
<property name="checkFormat" value="$1"/>
<!-- The check is suppressed in the next line of code after the comment -->
<property name="influenceFormat" value="1"/>
</module>
</module>
</module>

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.xit.core.spring.auth.mapper.IAuthMapper">
<!-- 일반 로그인 -->
<select id="login" resultType="egovframework.com.cmm.model.LoginVO">
<if test="userSe = 'USR'">
/** auth-mysql-mapper|login-로그인|julim */
SELECT user_id AS id
, user_nm AS name
, password
, ihidnum
, email_adres AS email
, 'USR' AS userSe
, orgnzt_id
, esntl_id
FROM xit_user_info
WHERE user_id = #{id}
AND password = #{password}
AND user_sttus_code = 'P'
</if>
</select>
<select id="selectUserById" resultType="egovframework.com.cmm.model.LoginVO">
<if test="userSe = 'USR'">
/** auth-mysql-mapper|selectUserById-사용자조회|julim */
SELECT user_id AS id
, user_nm AS name
, password
, ihidnum
, email_adres AS email
, 'USR' AS userSe
, orgnzt_id
, esntl_id
FROM xit_user_info
WHERE user_id = #{id}
AND user_sttus_code = 'P'
</if>
</select>
<insert id="saveRefreshToken">
</insert>
</mapper>

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
cacheEnabled 설정에서 각 mapper 에 설정된 캐시를 전역적으로 사용할지 말지에 대한 여부 true | false true
lazyLoadingEnabled 늦은 로딩을 사용할지에 대한 여부. 사용하지 않는다면 모두 즉시 로딩할 것이다. 이 값은 fetchType 속성을 사용해서 대체할 수 있다. true | false false
aggressiveLazyLoading 활성화 상태로 두게 되면 늦은(lazy) 로딩 프로퍼티를 가진 객체는 호출에 따라 로드될 것이다. 반면에 개별 프로퍼티는 요청할때 로드된다. true | false true
multipleResultSetsEnabled 한개의 구문에서 여러개의 ResultSet 을 허용할지의 여부(드라이버가 해당 기능을 지원해야 함) true | false true
useColumnLabel 칼럼명 대신에 칼럼라벨을 사용. 드라이버마다 조금 다르게 작동한다. 문서와 간단한 테스트를 통해 실제 기대하는 것처럼 작동하는지 확인해야 한다. true | false true
useGeneratedKeys 생성키에 대한 JDBC 지원을 허용. 지원하는 드라이버가 필요하다. true 로 설정하면 생성키를 강제로 생성한다. 일부 드라이버(예를들면, Derby)에서는 이 설정을 무시한다. true | false False
autoMappingBehavior MyBatis 가 칼럼을 필드/프로퍼티에 자동으로 매핑할지와 방법에 대해 명시. PARTIAL 은 간단한 자동매핑만 할뿐, 내포된 결과에 대해서는 처리하지 않는다. FULL 은 처리가능한 모든 자동매핑을 처리한다. NONE, PARTIAL, FULL PARTIAL
defaultExecutorType 디폴트 실행자(executor) 설정. SIMPLE 실행자는 특별히 하는 것이 없다. REUSE 실행자는 PreparedStatement 를 재사용한다. BATCH 실행자는 구문을 재사용하고 수정을 배치처리한다. SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 데이터베이스로의 응답을 얼마나 오래 기다릴지를 판단하는 타임아웃을 셋팅 양수 셋팅되지 않음(null)
safeRowBoundsEnabled 중첩구문내 RowBound 사용을 허용 true | false False
mapUnderscoreToCamelCase 전통적인 데이터베이스 칼럼명 형태인 A_COLUMN을 CamelCase형태의 자바 프로퍼티명 형태인 aColumn으로 자동으로 매핑하도록 함 true | false False
localCacheScope 마이바티스는 순환참조를 막거나 반복된 쿼리의 속도를 높히기 위해 로컬캐시를 사용한다. 디폴트 설정인 SESSION을 사용해서 동일 세션의 모든 쿼리를 캐시한다. localCacheScope=STATEMENT 로 설정하면 로컬 세션은 구문 실행할때만 사용하고 같은 SqlSession에서 두개의 다른 호출사이에는 데이터를 공유하지 않는다. SESSION | STATEMENT SESSION
jdbcTypeForNull JDBC타입을 파라미터에 제공하지 않을때 null값을 처리한 JDBC타입을 명시한다. 일부 드라이버는 칼럼의 JDBC타입을 정의하도록 요구하지만 대부분은 NULL, VARCHAR 나 OTHER 처럼 일반적인 값을 사용해서 동작한다. JdbcType 이늄. 대부분은 NULL, VARCHAR 나 OTHER 를 공통적으로 사용한다. OTHER
lazyLoadTriggerMethods 늦은 로딩을 야기하는 객체의 메소드를 명시 메소드 이름을 나열하고 여러개일 경우 콤마(,) 로 구분 equals,clone,hashCode,toString
defaultScriptingLanguage 동적으로 SQL을 만들기 위해 기본적으로 사용하는 언어를 명시 타입별칭이나 패키지 경로를 포함한 클래스명 org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls 가져온 값이 null일때 setter나 맵의 put 메소드를 호출할지를 명시 Map.keySet() 이나 null값을 초기화할때 유용하다. int, boolean 등과 같은 원시타입은 null을 셋팅할 수 없다는 점은 알아두면 좋다. true | false false
logPrefix 마이바티스가 로거(logger) 이름에 추가할 접두사 문자열을 명시 문자열 셋팅하지 않음
logImpl 마이바티스가 사용할 로깅 구현체를 명시 이 설정을 사용하지 않으면 마이바티스가 사용할 로깅 구현체를 자동으로 찾는다. SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 셋팅하지 않음
proxyFactory 마이바티스가 늦은 로딩을 처리할 객체를 생성할 때 사용할 프록시 툴을 명시 CGLIB | JAVASSIST CGLIB
-->
<settings>
<!--
Settings 설정 옵션 사이트 참조
-.사이트주소: https://postitforhooney.tistory.com/entry/MyBatisSetting-Mybatis%EC%97%90%EC%84%9C-%ED%95%84%EC%9A%94%ED%95%9C-%EB%B6%80%EB%B6%84%EB%93%A4-setting%EC%9E%90%EB%A3%8C
-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="cacheEnabled" value="true" />
<setting name="jdbcTypeForNull" value="VARCHAR" /><!-- NULL / VARCHAR / OTHER-->
<setting name="callSettersOnNulls" value="true"/> <!-- resultType으로 Map Collection 지정 시 value가 null일 떄 컬럼 누락문제 해결을 위한 설정 -->
<setting name="lazyLoadingEnabled" value="false" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGeneratedKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" /><!-- NONE / PARTIAL / FULL-->
<setting name="defaultExecutorType" value="SIMPLE" /><!-- SIMPLE / REUSE / BATCH-->
<setting name="defaultStatementTimeout" value="25" />
<setting name="safeRowBoundsEnabled" value="false" />
<setting name="localCacheScope" value="SESSION" /><!-- SESSION / STATEMENT-->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<setting name="aggressiveLazyLoading" value="true" />
</settings>
<!-- Type Aliases 설정-->
<!-- <typeAliases>-->
<!-- <typeAlias alias="egovMap" type="org.egovframe.rte.psl.dataaccess.util.EgovMap" />-->
<!-- <typeAlias alias="ComDefaultCodeVO" type="egovframework.com.cmm.model.ComDefaultCodeVO" />-->
<!-- <typeAlias alias="comDefaultVO" type="egovframework.com.cmm.model.ComDefaultVO" />-->
<!-- </typeAliases>-->
</configuration>

@ -1,7 +0,0 @@
#------------------------------------------------
# Admin \uBA54\uC138\uC9C0 \uC815\uC758
#------------------------------------------------
fail.auth.header.invalid=header\uAC00 \uC5C6\uAC70\uB098, \uD615\uC2DD\uC774 \uD2C0\uB9BD\uB2C8\uB2E4({0})
fail.auth.login.user=\uC0AC\uC6A9\uC790(\uD68C\uC6D0) \uC815\uBCF4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.

@ -1,3 +0,0 @@
#------------------------------------------------
# Admin \uBA54\uC138\uC9C0 \uC815\uC758
#------------------------------------------------

@ -1,3 +0,0 @@
#------------------------------------------------
# Admin \uBA54\uC138\uC9C0 \uC815\uC758
#------------------------------------------------

@ -1,183 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!--
logback-spring.xml 로 설정시 스프링의 환경변수를 로그백 시스템 환경변수로 사용
logging.file.name => LOG_FILE, logging.file.path => LOG_PATH
logging.charset.console / file => CONSOLE_LOG_CHARSET, FILE_LOG_CHARSET
-->
<!-- async rolling appender 사용시 로그의 class, method, line number 출력 제어 : 성능저하 이슈 -->
<springProfile name="local, dev">
<property name="isIncludeCallerData" value="true"/>
</springProfile>
<springProfile name="prod">
<property name="isIncludeCallerData" value="false"/>
</springProfile>
<!-- ============================================================================= -->
<!-- console logging Appender defined -->
<!-- ============================================================================= -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 기본 출력 로그 제거 -->
<Filter class="kr.xit.core.support.logback.ExcludeLogFilter"/>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>${CONSOLE_LOG_CHARSET}</charset>
</encoder>
</appender>
<!-- ============================================================================= -->
<!-- ============================================================================= -->
<!-- file logging Appender defined -->
<!-- ============================================================================= -->
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<!-- 다른 수준의 레벨은 기록하지 않는다.(상위 레벨도 기록 안함), 상위 수준의 레벨에 대한 기록을 원하면 ACCEPT 로 하면 기록된다. -->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!-- 기본 출력 로그 제거 -->
<!--Filter class="kr.xit.core.support.logback.ExcludeLogFilter"/-->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${FILE_LOG_CHARSET}</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/backup/${LOG_FILE}_%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>30MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>50</maxHistory>
</rollingPolicy>
</appender>
<!-- async appender defined -->
<!-- includeCallerData=true -->
<appender name="ASYNC_ROLLING" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="ROLLING"/>
<!-- blocking queue의 최대 수용 갯수로 기본값은 256 -->
<queueSize>2048</queueSize>
<discardingThreshold>20</discardingThreshold>
<!-- 해당 시간안에 처리하지 못한 이벤트는 삭제 : 단위 - ms -->
<maxFlushTime>6000</maxFlushTime>
<!--큐가 가득찬 상황에서 메세지 유실을 방지하기 위해 application block 할지 여부 -->
<!-- true로 설정된 경우 application을 멈추지 않기 위해 메세지를 버린다 -->
<neverBlock>true</neverBlock>
<!-- 메소드명, 라인번호 출력 : 성능저하 요인 -->
<includeCallerData>${isIncludeCallerData}</includeCallerData>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- ============================================================================= -->
<!-- ============================================================================= -->
<!-- logging mask defined -->
<!-- ============================================================================= -->
<appender name="mask" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="kr.xit.core.support.logback.LogbackMaskingPatternLayout">
<maskPattern>\"juminId\"\s*:\s*\"(.*?)\"</maskPattern> <!-- SSN JSON pattern -->
<maskPattern>\"recveJuminno\"\s*:\s*\"(.*?)\"</maskPattern> <!-- SSN JSON pattern -->
<maskPattern>\"recevAddr\"\s*:\s*\"(.*?)\"</maskPattern> <!-- Address JSON pattern -->
<maskPattern>\"recevDetailAddr\"\s*:\s*\"(.*?)\"</maskPattern> <!-- Address JSON pattern -->
<pattern>%-5p [%d{ISO8601,UTC}] [%thread] %c: %m%n%rootException</pattern>
</layout>
</encoder>
</appender>
<!-- ============================================================================= -->
<!-- ************************************************************************* -->
<!-- SQL log : root appender로 로그 전파 - additivity="true" -->
<!-- ************************************************************************* -->
<!-- DB transaction -->
<logger name="org.mybatis.spring.SqlSessionUtils" level="DEBUG" />
<!-- log4jdbc 옵션 설정 -->
<logger name="jdbc" level="OFF"/>
<springProfile name="prod">
<!-- 운영 환경에서만 sql문 및 결과 출력하지 않음 -->
<!-- SQL문과 소요된 시간 -->
<logger name="jdbc.sqltiming" level="OFF"/>
<!-- SQL 결과 조회된 데이터를 table 형식으로 출력 -->
<logger name="jdbc.resultsettable" level="OFF"/>
</springProfile>
<springProfile name="local, dev">
<!-- 로컬, 개발 환경에서는 sql문 및 결과 출력 -->
<!-- SQL문과 소요된 시간 -->
<logger name="jdbc.sqltiming" level="DEBUG" />
<!-- SQL 결과 조회된 데이터를 table 형식으로 출력 -->
<logger name="jdbc.resultsettable" level="DEBUG" />
</springProfile>
<!-- SQL문 출력 -->
<logger name="jdbc.sqlonly" level="OFF"/>
<!-- result를 포함한 모든 JDBC 호출 정보 -->
<logger name="jdbc.resultset" level="OFF"/>
<!-- DB connection open/close -->
<logger name="jdbc.connection" level="OFF"/>
<!-- resultset을 제외한 JDBC 호출 정보 -->
<logger name="jdbc.audit" level="OFF"/>
<logger name="org.mariadb.jdbc" level="ERROR"/>
<!-- DB Connection Pool 관련 -->
<logger name="com.zaxxer.hikari.pool.PoolBase" level="ERROR" />
<logger name="com.zaxxer.hikari.pool.HikariPool" level="ERROR" />
<logger name="com.zaxxer.hikari.HikariDataSource" level="ERROR" />
<!-- ************************************************************************* -->
<!-- SQL log -->
<!-- ************************************************************************* -->
<!-- ************************************************************************* -->
<!-- spring / 3rdparty log : root appender로 로그 전파 - additivity="true" -->
<!-- ************************************************************************* -->
<logger name="io.swagger.v3.core.converter" level="INFO"/>
<logger name="org.egovframe.rte.fdl.cmmn.exception.manager" level="INFO"/>
<logger name="org.egovframe.rte.fdl.cmmn.aspect.ExceptionTransfer" level="INFO"/>
<logger name="org.egovframe" level="ERROR"/>
<logger name="org.apache.commons" level="INFO"/>
<logger name="com.zaxxer.hikari.pool.HikariPool" level="INFO"/>
<!-- ************************************************************************* -->
<!-- spring / 3rdparty log -->
<!-- ************************************************************************* -->
<!-- ************************************************************************* -->
<!-- application log : root appender로 로그 전파 - additivity="true" -->
<!-- ************************************************************************* -->
<!-- <logger name="org.springframework.web.filter.MustRequestLoggingFilter" level="DEBUG" additivity="false"/>-->
<!--logger name="kr.xit.core.filter.CustomRequestLoggingFilter" level="DEBUG"/-->
<logger name="kr.xit" level="DEBUG"/>
<!-- ************************************************************************* -->
<!-- application log -->
<!-- ************************************************************************* -->
<!-- ************************************************************************* -->
<!-- root logging -->
<!-- ************************************************************************* -->
<root level="DEBUG">
<springProfile name="prod">
<appender-ref ref="ASYNC_ROLLING"/>
</springProfile>
<springProfile name="local, dev">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ASYNC_ROLLING"/>
</springProfile>
</root>
</configuration>

@ -1,66 +0,0 @@
<!DOCTYPE HTML>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/resources/static/semantic/dist/semantic.min.css">
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<script src="/resources/static/semantic/dist/semantic.min.js"></script>
<title>login</title>
</head>
<body>
<form class="ui form">
<div class="field">
<label>id</label>
<input type="text" name="id" placeholder="사용자 ID" value="admin">
</div>
<div class="field">
<label>password</label>
<input type="text" name="password" placeholder="비밀번호" value="1">
</div>
<div class="field">
<div class="ui checkbox">
<input type="checkbox" tabindex="0" class="hidden">
<label>id 저장</label>
</div>
</div>
<input type="hidden" name="userSe" value="USR">
<button class="ui button" type="submit">Submit</button>
</form>
</body>
<script>
const postForm = (body) => {
return fetch('/auth/loginJwt', {
method: 'POST',
headers: {
'X-APP-CHANNEL': 'WEB',
'X-FORWORD-FOR': '211.119.124.73',
'Content-Type': 'application/json'
},
body
});
};
const handleSubmit = async (e) => {
e.preventDefault();
const form = document.querySelector('form');
const data = Object.fromEntries(new FormData(form).entries());
// const body = {
// id: document.querySelector('input[name="id"]').value,
// password: document.querySelector('input[name="password"]').value,
// userSe: document.querySelector('input[name="userSe"]').value,
// }
const res = await postForm(JSON.stringify(data))
const json = await res.json();
console.log(json)
};
document.querySelector('form').addEventListener("click", handleSubmit);
</script>
</html>

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Title</title>
</head>
<body>
<p>Error</p>
</body>
</html>

@ -1,16 +0,0 @@
<!DOCTYPE HTML>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>전자고지 API Framework</title>
</head>
<body>
<h3>전자고지 API Framework</h3>
<p>
<a href="http://localhost:8081/swagger-ui.html">API Document</a>
</p>
<p>
자세한 사항은 README.md 참고
</p>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -61,13 +61,13 @@ app:
## 암호화(license) 적용
### 모듈 import : xit-init.jar
### 모듈 package : kr.xit.init
-> 복호화 메소드만 제공
```text
1. /resources/META-INF/spring.factories 파일 생성
# META-INF/spring.factories : xit-init
org.springframework.context.ApplicationContextInitializer=xit.core.init.custom.CustomContextInitalizer
org.springframework.context.ApplicationContextInitializer=kr.xit.core.init.custom.CustomContextInitalizer
```
### 정보(license) 암호화
```text

@ -18,12 +18,6 @@
<dependencies>
<dependency>
<groupId>kr.xit</groupId>
<artifactId>xit-init</artifactId>
<version>${project.version}</version>
</dependency>
<!-- migration 완료후 제거 -->
<!--
<dependency>
@ -459,6 +453,19 @@
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${project.name}</finalName>
<!-- 코드 난독화 : proguard-->
<pluginManagement>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>${proguard-plugin-version}</version>
</plugin>
</plugins>
</pluginManagement>
<!-- 코드 난독화 : proguard -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -469,6 +476,70 @@
</excludes>
</configuration>
</plugin>
<!-- proguard -->
<!--
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<addMavenDescriptor>false</addMavenDescriptor>
<proguardInclude>proguard.cfg</proguardInclude>
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<injarNotExistsSkip>true</injarNotExistsSkip>
<options>
<option>-target 17</option>
<option>-dontshrink</option>
<option>-dontnote</option>
<option>-dontwarn</option>
<option>-keepparameternames</option>
<option>-renamesourcefileattribute SourceFile</option>
<option>-keepattributes Signature,Exceptions,*Annotation*,
InnerClasses,PermittedSubclasses,EnclosingMethod,
Deprecated,SourceFile,LineNumberTable
</option>
<option>-keep public class * {
public protected *;
}
</option>
<option>-keepclasseswithmembernames,includedescriptorclasses class * {
native <![CDATA[<methods>]]>;
}
</option>
<option>-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
</option>
<option>-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
</option>
</options>
<libs>
<lib>${java.home}/jmods/java.base.jmod</lib>
</libs>
</configuration>
</plugin-->
</plugins>
</build>
</project>

@ -1,4 +1,4 @@
package xit.core.init.custom;
package kr.xit.core.init.custom;
import java.net.InetAddress;
import java.net.NetworkInterface;
@ -9,11 +9,11 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import kr.xit.core.init.custom.bouncy.BouncyDecUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import xit.core.init.custom.bouncy.BouncyDecUtils;
/**
* <pre>
@ -25,7 +25,7 @@ import xit.core.init.custom.bouncy.BouncyDecUtils;
* data2 - primary DB info
* data3 - secondary DB info
*
* packageName : kr.xit.core.spring.config.custom
* packageName : kr.xit.core.init.config.custom
* fileName : AppInitHelper
* author : limju
* date : 2023-07-24
@ -38,7 +38,7 @@ import xit.core.init.custom.bouncy.BouncyDecUtils;
*/
@Slf4j
public class AppInitHelper {
private ConfigurableApplicationContext applicationContext;
private final ConfigurableApplicationContext applicationContext;
/**
* Instantiates a new App init helper.

@ -1,17 +1,16 @@
package xit.core.init.custom;
package kr.xit.core.init.custom;
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Arrays;
/**
* <pre>
* description : license
* -> local
*
* packageName : kr.xit.core.spring.custom
* packageName : kr.xit.core.init.custom
* fileName : CustomContextInitalizer
* author : limju
* date : 2023-07-21
@ -22,6 +21,7 @@ import java.util.Arrays;
*
* </pre>
*/
@SuppressWarnings("rawtypes")
@Slf4j
public class CustomContextInitalizer implements ApplicationContextInitializer {
/**

@ -1,13 +1,5 @@
package xit.core.init.custom.bouncy;
package kr.xit.core.init.custom.bouncy;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -19,6 +11,13 @@ import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
/**
* <pre>

@ -29,14 +29,14 @@ import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import xit.core.init.custom.bouncy.BouncyDecUtils;
import kr.xit.core.init.custom.bouncy.BouncyDecUtils;
/**
* <pre>
* description : DSA / / Utils
* DSA(Digital Signature Algorithm) /
* -> bouncycastle /
* packageName : kr.xit.core.spring.config.custom.bouncy
* packageName : kr.xit.core.init.custom.bouncy
* fileName : BouncyUtils
* author : limju
* date : 2023-07-20

@ -11,11 +11,9 @@
<description>Mobile Electronic Notice System Root pom</description>
<modules>
<module>xit-init</module>
<module>mens-core</module>
<module>mens-api</module>
<module>mens-batch</module>
<module>mens-admin</module>
</modules>
<properties>

@ -1,33 +0,0 @@
README.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

@ -1,143 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>kr.xit</groupId>
<artifactId>mens-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>xit-init</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>xit-init</name>
<description>xit-init</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- migration 완료후 제거 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
<!-- migration 완료후 제거 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<!-- proguard -->
<dependency>
<groupId>com.guardsquare</groupId>
<artifactId>proguard-base</artifactId>
<version>${proguard-base-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.guardsquare</groupId>
<artifactId>proguard-core</artifactId>
<version>${proguard-core-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${project.name}</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>${proguard-plugin-version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<!-- proguard -->
<!--
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<addMavenDescriptor>false</addMavenDescriptor>
<proguardInclude>proguard.cfg</proguardInclude>
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<injarNotExistsSkip>true</injarNotExistsSkip>
<options>
<option>-target 17</option>
<option>-dontshrink</option>
<option>-dontnote</option>
<option>-dontwarn</option>
<option>-keepparameternames</option>
<option>-renamesourcefileattribute SourceFile</option>
<option>-keepattributes Signature,Exceptions,*Annotation*,
InnerClasses,PermittedSubclasses,EnclosingMethod,
Deprecated,SourceFile,LineNumberTable
</option>
<option>-keep public class * {
public protected *;
}
</option>
<option>-keepclasseswithmembernames,includedescriptorclasses class * {
native <![CDATA[<methods>]]>;
}
</option>
<option>-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
</option>
<option>-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
</option>
</options>
<libs>
<lib>${java.home}/jmods/java.base.jmod</lib>
</libs>
</configuration>
</plugin-->
</plugins>
</build>
</project>
Loading…
Cancel
Save