diff --git a/egovframe-template-simple-react-contribution/src/constants/url.js b/egovframe-template-simple-react-contribution/src/constants/url.js
index 32ddaa5..9be2671 100644
--- a/egovframe-template-simple-react-contribution/src/constants/url.js
+++ b/egovframe-template-simple-react-contribution/src/constants/url.js
@@ -4,7 +4,8 @@ const URL = {
MAIN : "/", //메인페이지
LOGIN : "/login", //로그인
- ERROR : "/error", //로그인
+ JOIN : "/join", //회원가입
+ ERROR : "/error", //에러
//ABOUT
ABOUT : "/about", //사이트소개
diff --git a/egovframe-template-simple-react-contribution/src/css/base.css b/egovframe-template-simple-react-contribution/src/css/base.css
index 1e1a118..4c4bf41 100644
--- a/egovframe-template-simple-react-contribution/src/css/base.css
+++ b/egovframe-template-simple-react-contribution/src/css/base.css
@@ -84,4 +84,4 @@ button {cursor: pointer;}
.detailInfoDiv > div > p { display: inline; }
-.detailInfoDiv > div > input {margin-right: 5px;}
\ No newline at end of file
+.detailInfoDiv > div > input {margin-right: 5px;}
diff --git a/egovframe-template-simple-react-contribution/src/css/page.css b/egovframe-template-simple-react-contribution/src/css/page.css
index cd87aed..b219bcd 100644
--- a/egovframe-template-simple-react-contribution/src/css/page.css
+++ b/egovframe-template-simple-react-contribution/src/css/page.css
@@ -12,13 +12,26 @@
.Plogin .login_box input[type=password]:-ms-input-placeholder {color: #aaa; opacity: 1;}
.Plogin .login_box button {display: block; position: absolute; left: 435px; top: 70px; width: 160px; height: 110px; border-radius: 8px; color: #fff; font-size: 20px; font-weight: 500; text-align: center; line-height: 110px; background: #169bd5;}
.Plogin .login_box button span {display: block; position: relative; height: 100%;}
-.Plogin .login_box .chk {margin-top: 20px; font-size: 0;}
+.Plogin .login_box .chk {margin-top: 20px;}
.Plogin .login_box .chk em {display: inline-block; height: 30px; margin-left: 40px; color: #666; font-size: 16px;}
.Plogin .list {margin-top: 44px; padding: 0 360px;}
.Plogin .list li {position: relative; padding-left: 15px; color: #666; font-size: 16px; line-height: 26px;}
.Plogin .list li::before {content: ""; display: block; position: absolute; left: 0; top: 12px; width: 4px; height: 4px; background: #666;}
.Plogin .list li + li {margin-top: 5px;}
+.Pjoin h1 {color: #222; font-size: 48px; font-weight: 500; letter-spacing: -2px; line-height: 48px; text-align: center;}
+.Pjoin .join_box {position: relative; width: 690px; margin: 54px auto 0; padding: 70px 95px 120px 95px ; border: 1px solid #dde2e5; border-radius: 25px; box-shadow: 3px 4px 5px #ccc;}
+.Pjoin .join_box input[type=text],
+.Pjoin .join_box input[type=password] {width: 100%; height: 46px; padding: 0 20px; border: 0; border-radius: 8px; color: #666; font-size: 16px; background: #f5f5f5;}
+.Pjoin .join_box .group input + input {margin-top: 18px;}
+.Pjoin .join_box input[type=text]:-ms-input-placeholder,
+.Pjoin .join_box input[type=password]:-ms-input-placeholder {color: #aaa; opacity: 1;}
+.Pjoin .join_box .chk {margin-top: 20px;}
+.Pjoin .join_box .chk em {display: inline-block; height: 30px; margin-left: 40px; color: #666; font-size: 16px;}
+.Pjoin .join_box button {width: 500px;height: 50px;border-radius: 8px;color: #fff;font-size: 20px;font-weight: 500;text-align: center;line-height: 50px;background: #169bd5;}
+.Pjoin .join_box button span {display: block; position: relative; height: 100%;}
+.Pjoin .join_box .list li {position: relative; padding-left: 15px; color: #666; font-size: 16px; line-height: 26px;}
+.Pjoin .join_box .list li + li {margin-top: 5px;}
/* Board */
diff --git a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx
index 040cd88..2b1698e 100644
--- a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx
+++ b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx
@@ -1,9 +1,12 @@
import React, { useState, useEffect, useRef } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
+import {Link, useLocation, useNavigate} from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import CODE from 'constants/code';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+
import { getLocalItem, setLocalItem, setSessionItem } from 'utils/storage';
function EgovLoginContent(props) {
@@ -113,11 +116,16 @@ function EgovLoginContent(props) {
setUserInfo({ ...userInfo, password: e.target.value })} />
-
-
-
+
+
+
+
+
+ 회원가입
+
+
diff --git a/egovframe-template-simple-react-contribution/src/pages/login/join/InfoShareChk.jsx b/egovframe-template-simple-react-contribution/src/pages/login/join/InfoShareChk.jsx
new file mode 100644
index 0000000..140969f
--- /dev/null
+++ b/egovframe-template-simple-react-contribution/src/pages/login/join/InfoShareChk.jsx
@@ -0,0 +1,20 @@
+import React from 'react'
+
+function InfoShareChk() {
+ return (
+
+ - 건설기준 포털시스템(KCSC)은 회원님께 원활한 서비스 제공을 위해 최소한의 개인정보를 수집하고 있으며, 각 목적 별로 수집하는 개인정보를 다음과 같이 정하고 있습니다.
+ -
+ - ◌ 수집하는 개인정보의 항목
+ - 수집항목: 아이디(ID), 비밀번호, 이메일(e-mail)
+ - ◌ 개인정보의 수집 및 이용 목적
+ - 이용목적 : 건설기준 포털시스템(KCSC) 회원가입 및 Q&A 작성
+ - ◌ 개인정보의 보류 및 이용기간
+ - 회원가입정보 : 탈퇴시까지
+ - ◌ 정보주체의 동의 거부 권리 및 그에 따른 불이익 사항
+ -
+ - 귀하는 건설기준 포털시스템(KCSC) 이용을 위한 개인정보의 수집·이용 동의를 거부할 권리가 있습니다. 다만, 개인정보의 수집·이용 동의를 거부할 경우 건설기준 포털시스템(KCSC) 일부 기능에 대한 서비스 이용에 제한을 받으실 수 있습니다.
+
+ )
+}
+export default InfoShareChk;
\ No newline at end of file
diff --git a/egovframe-template-simple-react-contribution/src/pages/login/join/Join.jsx b/egovframe-template-simple-react-contribution/src/pages/login/join/Join.jsx
new file mode 100644
index 0000000..b3f9968
--- /dev/null
+++ b/egovframe-template-simple-react-contribution/src/pages/login/join/Join.jsx
@@ -0,0 +1,116 @@
+import React, { useState, useEffect, useRef } from 'react';
+import {Link, useLocation, useNavigate} from 'react-router-dom';
+import * as EgovNet from 'api/egovFetch';
+
+import URL from 'constants/url';
+import CODE from 'constants/code';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+
+import { getLocalItem, setLocalItem, setSessionItem } from 'utils/storage';
+import EgovLoginContent from "../EgovLoginContent";
+import InfoShareChk from "./InfoShareChk";
+
+function Join(props) {
+ console.group("JoinContent");
+ console.log("[Start] JoinContent ------------------------------");
+ console.log("JoinContent [props] : ", props);
+
+ const navigate = useNavigate();
+ const location = useLocation();
+ console.log("JoinContent [location] : ", location);
+
+ const [userInfo, setUserInfo] = useState({ id: '', email: '', password: '' });
+ const [infoShareChk, setInfoShareChk] = useState(false);
+
+ const submitFormHandler = (e) => {
+ console.log("JoinContent submitFormHandler()");
+
+ const loginUrl = "/auth/join"
+ const requestOptions = {
+ method: "POST",
+ headers: {
+ 'Content-type': 'application/json'
+ },
+ body: JSON.stringify(userInfo)
+ }
+
+ EgovNet.requestFetch(loginUrl,
+ requestOptions,
+ (resp) => {
+ let resultVO = resp.resultVO;
+ let jToken = resp?.jToken || null;
+
+ setSessionItem('jToken', jToken);
+
+
+ })
+ }
+
+ console.log("------------------------------JoinContent [End]");
+ console.groupEnd("JoinContent");
+
+ const infoShareBtn = () =>{
+ setInfoShareChk(true)
+ }
+
+ return (
+
+
+ {/* */}
+
+ {/* */}
+
+
+
+ {/* */}
+
+
회원가입
+
+ {infoShareChk?(
+
+ ):(
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ {/* */}
+
+
+
+
+ );
+}
+
+export default Join;
\ No newline at end of file
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js
new file mode 100644
index 0000000..9a4bc40
--- /dev/null
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js
@@ -0,0 +1,171 @@
+import * as EgovNet from "../../api/egovFetch";
+import React, {useEffect, useState} from "react";
+import SbItem from "./SbItem";
+import {Col, Row} from "react-bootstrap";
+import {VwDiv, VwPtag} from "./Sb.style";
+
+/*최상위 컴포넌트*/
+export function Maincontent({docCode}) {
+ const [doccode, setdoccode] = useState('');
+ const [docname, setdocname] = useState('');
+//TODO 맨처음 목차코드 및 목차제목 안나오는 문제 수정
+ function setdoccodandname(doccode, docname) {
+ setdoccode(doccode);
+ setdocname(docname);
+ }
+
+
+ return (
+
+
{doccode+' '+docname}
+
+
+
+
+ )
+}
+
+/*글 트리 컴포넌트*/
+export function CodeTree({docCode, setdoccodandname}) {
+ const [codeTree, setcodeTree] = useState([]);
+ const [doccode, setdoccode] = useState(docCode);
+ let data = [];
+ const getCodeTree = () => {
+ EgovNet.requestFetch(
+ '/standardCode/getCodeTree.do',
+ {
+ method: "POST",
+ headers: {
+ 'Content-type': 'application/json'
+ },
+ body: JSON.stringify({})
+ }, (item) => {
+ data = item.result.codeTree;
+ const nest = (menuData, parent_seq = null, link = 'parent_seq') =>
+ menuData.filter(item => item[link] === parent_seq)
+ .map(item => ({...item, childrens: nest(menuData, item.seq)}));
+ setcodeTree(nest(data));
+ }, () => {
+ })
+ }
+ useEffect(() => {
+ getCodeTree()
+ }, [])
+
+ return (
+ {codeTree.map(resp => {
+ return (
+
+ )
+ }
+ )}
+ )
+}
+
+
+/*글 내용+목차 분리 컴포넌트*/
+//TODO 추가 분리 작업 필요
+export function CodeCotentData({docCode}) {
+ const [codeChapter, setcodeChapter] = useState([]);
+ const [codeContent, setcodeContetn] = useState([]);
+ let result =[];
+ const getCodeDetail = (docCode) => {
+ EgovNet.requestFetch(
+ '/standardCode/getCodeDetailInfo.do',
+ {
+ method: "POST",
+ headers: {
+ 'Content-type': 'application/json'
+ },
+ body: JSON.stringify({
+ docCode: docCode
+ })
+ }, (item) => {
+ result = item.result.document;
+ }, () => {
+ })
+ }
+ useEffect(() => {
+ getCodeDetail(docCode)
+ setcodeChapter(result.map(item =>{
+ const isTitle = item.full_content.includes(item.group_title);
+ return(
+
+ {
+ document.location.hash="#"+item.cont_type_cd;
+ }} dangerouslySetInnerHTML={ {__html: item.group_title} }>
+
+
+ )
+ }))
+ setcodeContetn(result.map(item =>{
+ const isTitle = item.full_content.includes(item.group_title);
+ const docLinkReg = /([A-Z]{3,5}(\s[0-9]{2}){3,4})/g
+ const docPartReg = /\((?:표|그림|부록)?\s*([A-Z]\.)?(?!\d\))\d+(\.\d+)*(\s?\(\d\))?(-\d+)?(?:\s*[A-Z])?\)/g
+ if(docLinkReg.test(item.full_content)){
+ const docCodeAry = item.full_content.match(docLinkReg);
+ const docCodeMap = new Map();
+ for(let i=0; i' + docCode + '')
+ }
+ docCodeMap.forEach((docCodeLink, docCode)=>{
+ item.full_content = item.full_content.replaceAll(docCode, docCodeLink);
+ })
+ if(docPartReg.test(item.full_content)){
+
+ const docPartAry = item.full_content.match(docPartReg);
+ const docPartMap = new Map();
+ for(let i=0; i'+
+ ''+
+ '');
+ }
+ docPartMap.forEach((docPartLink, docPart)=>{
+ item.full_content = item.full_content.replaceAll(docPart, docPartLink);
+ })
+ }
+ if(item.full_content.includes(""+item.full_content;
+ }
+ item.full_content = item.full_content+"
"
+ return(
+
+ )
+ }
+ }))
+ }, [docCode])
+
+ return (<>
+
+
+ >)
+}
+
+
+
+
+
+
+
+
+/*글 목차 컴포넌트*/
+export function CodeChapter({codeChapter}) {
+ return (<>{codeChapter}>)
+}
+
+/*글 내용 컴포넌트*/
+export function CodeContent({codeContent}) {
+ return (<>{codeContent}>)
+}
\ No newline at end of file
diff --git a/egovframe-template-simple-react-contribution/src/routes/index.jsx b/egovframe-template-simple-react-contribution/src/routes/index.jsx
index b0cd134..76831b2 100644
--- a/egovframe-template-simple-react-contribution/src/routes/index.jsx
+++ b/egovframe-template-simple-react-contribution/src/routes/index.jsx
@@ -12,6 +12,7 @@ import EgovError from 'components/EgovError';
import EgovMain from 'pages/main/EgovMain';
import EgovLogin from 'pages/login/EgovLogin';
+import Join from 'pages/login/join/Join';
//ABOUT
import EgovAboutSite from 'pages/about/EgovAboutSite';
@@ -146,9 +147,9 @@ const SecondRoutes = () => {
} />
{/* LOGIN */}
- setLoginVO(user)}
- />}/>
+ setLoginVO(user)}/>}/>
+ {/*{JOIN}*/}
+ } />
{/* ERROR */}
} />
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/EgovLoginApiController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/EgovLoginApiController.java
new file mode 100644
index 0000000..9e1d755
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/EgovLoginApiController.java
@@ -0,0 +1,190 @@
+package com.dbnt.kcscbackend.auth;
+
+import com.dbnt.kcscbackend.auth.service.EgovLoginService;
+import com.dbnt.kcscbackend.config.common.BaseController;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
+import com.dbnt.kcscbackend.config.common.ResponseCode;
+import com.dbnt.kcscbackend.config.common.ResultVO;
+import com.dbnt.kcscbackend.config.egov.EgovMessageSource;
+import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+
+/**
+ * 일반 로그인을 처리하는 컨트롤러 클래스
+ * @author 공통서비스 개발팀 박지욱
+ * @since 2009.03.06
+ * @version 1.0
+ * @see
+ *
+ *
+ * << 개정이력(Modification Information) >>
+ *
+ * 수정일 수정자 수정내용
+ * ------- -------- ---------------------------
+ * 2009.03.06 박지욱 최초 생성
+ * 2011.08.31 JJY 경량환경 템플릿 커스터마이징버전 생성
+ *
+ *
+ */
+
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/auth")
+@Tag(name="EgovLoginApiController",description = "로그인 관련")
+public class EgovLoginApiController extends BaseController {
+
+ /** EgovLoginService */
+ private EgovLoginService loginService;
+
+ /** EgovMessageSource */
+ @Resource(name = "egovMessageSource")
+ EgovMessageSource egovMessageSource;
+
+ /** JWT */
+ @Autowired
+ private EgovJwtTokenUtil jwtTokenUtil;
+
+
+ @Operation(
+ summary = "JWT 로그인",
+ description = "JWT 로그인 처리",
+ tags = {"EgovLoginApiController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "로그인 성공"),
+ @ApiResponse(responseCode = "300", description = "로그인 실패")
+ })
+ @PostMapping(value = "/join")
+ public HashMap actionJoin(@RequestBody LoginVO loginVO, HttpServletRequest request) throws Exception {
+ HashMap resultMap = new HashMap();
+
+ return resultMap;
+ }
+
+ /**
+ * 일반 로그인을 처리한다
+ * @param loginVO - 아이디, 비밀번호가 담긴 LoginVO
+ * @param request - 세션처리를 위한 HttpServletRequest
+ * @return result - 로그인결과(세션정보)
+ * @exception Exception
+ */
+
+ @Operation(
+ summary = "일반 로그인",
+ description = "일반 로그인 처리",
+ tags = {"EgovLoginApiController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "로그인 성공"),
+ @ApiResponse(responseCode = "300", description = "로그인 실패")
+ })
+ @PostMapping(value = "/login", consumes = {MediaType.APPLICATION_JSON_VALUE , MediaType.TEXT_HTML_VALUE})
+ public HashMap actionLogin(@RequestBody LoginVO loginVO, HttpServletRequest request) throws Exception {
+ HashMap resultMap = new HashMap();
+
+ // 1. 일반 로그인 처리
+ LoginVO loginResultVO = loginService.actionLogin(loginVO);
+
+ if (loginResultVO != null && loginResultVO.getId() != null && !loginResultVO.getId().equals("")) {
+
+ request.getSession().setAttribute("LoginVO", loginResultVO);
+ resultMap.put("resultVO", loginResultVO);
+ resultMap.put("resultCode", "200");
+ resultMap.put("resultMessage", "성공 !!!");
+ } else {
+ resultMap.put("resultVO", loginResultVO);
+ resultMap.put("resultCode", "300");
+ resultMap.put("resultMessage", egovMessageSource.getMessage("fail.common.login"));
+ }
+
+ return resultMap;
+
+ }
+
+ @Operation(
+ summary = "JWT 로그인",
+ description = "JWT 로그인 처리",
+ tags = {"EgovLoginApiController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "로그인 성공"),
+ @ApiResponse(responseCode = "300", description = "로그인 실패")
+ })
+ @PostMapping(value = "/login-jwt")
+ public HashMap actionLoginJWT(@RequestBody LoginVO loginVO, HttpServletRequest request, ModelMap model) throws Exception {
+ HashMap resultMap = new HashMap();
+
+ // 1. 일반 로그인 처리
+ LoginVO loginResultVO = loginService.actionLogin(loginVO);
+
+ if (loginResultVO != null && loginResultVO.getId() != null && !loginResultVO.getId().equals("")) {
+
+ log.debug("===>>> loginVO.getUserSe() = "+loginVO.getUserSe());
+ log.debug("===>>> loginVO.getId() = "+loginVO.getId());
+ log.debug("===>>> loginVO.getPassword() = "+loginVO.getPassword());
+
+ String jwtToken = jwtTokenUtil.generateToken(loginResultVO);
+
+ String username = jwtTokenUtil.getUserSeFromToken(jwtToken);
+ log.debug("Dec jwtToken username = "+username);
+
+ //서버사이드 권한 체크 통과를 위해 삽입
+ //EgovUserDetailsHelper.isAuthenticated() 가 그 역할 수행. DB에 정보가 없으면 403을 돌려 줌. 로그인으로 튕기는 건 프론트 쪽에서 처리
+ request.getSession().setAttribute("LoginVO", loginResultVO);
+
+ resultMap.put("resultVO", loginResultVO);
+ resultMap.put("jToken", jwtToken);
+ resultMap.put("resultCode", "200");
+ resultMap.put("resultMessage", "성공 !!!");
+
+ } else {
+ resultMap.put("resultVO", loginResultVO);
+ resultMap.put("resultCode", "300");
+ resultMap.put("resultMessage", egovMessageSource.getMessage("fail.common.login"));
+ }
+
+ return resultMap;
+ }
+
+ /**
+ * 로그아웃한다.
+ * @return resultVO
+ * @exception Exception
+ */
+ @Operation(
+ summary = "로그아웃",
+ description = "로그아웃 처리(JWT,일반 관계 없이)",
+ tags = {"EgovLoginApiController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "로그아웃 성공"),
+ })
+ @GetMapping(value = "/logout")
+ public ResultVO actionLogoutJSON(HttpServletRequest request, HttpServletResponse response) throws Exception {
+
+ ResultVO resultVO = new ResultVO();
+
+ new SecurityContextLogoutHandler().logout(request, response, null);
+
+ resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
+ resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
+
+ return resultVO;
+ }
+}
\ No newline at end of file
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/common/LoginVO.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
similarity index 97%
rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/common/LoginVO.java
rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
index 6f84b1d..25e339d 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/common/LoginVO.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
@@ -1,4 +1,4 @@
-package com.dbnt.kcscbackend.config.common;
+package com.dbnt.kcscbackend.auth.entity;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -38,7 +38,7 @@ public class LoginVO implements Serializable{
@Schema(description = "이름")
private String name;
-
+
@Schema(description = "주민등록번호")
private String ihidNum;
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/mapper/LoginUserMapper.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/mapper/LoginUserMapper.java
new file mode 100644
index 0000000..73411d0
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/mapper/LoginUserMapper.java
@@ -0,0 +1,56 @@
+package com.dbnt.kcscbackend.auth.mapper;
+
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 일반 로그인을 처리하는 비즈니스 구현 클래스
+ * @author 공통서비스 개발팀 박지욱
+ * @since 2009.03.06
+ * @version 1.0
+ * @see
+ *
+ *
+ * << 개정이력(Modification Information) >>
+ *
+ * 수정일 수정자 수정내용
+ * ------- -------- ---------------------------
+ * 2009.03.06 박지욱 최초 생성
+ * 2011.08.31 JJY 경량환경 템플릿 커스터마이징버전 생성
+ *
+ *
+ */
+@Mapper
+public interface LoginUserMapper {
+
+ /**
+ * 일반 로그인을 처리한다
+ * @param vo LoginVO
+ * @return LoginVO
+ * @exception Exception
+ */
+ LoginVO actionLogin(LoginVO vo);
+
+ /**
+ * 아이디를 찾는다.
+ * @param vo LoginVO
+ * @return LoginVO
+ * @exception Exception
+ */
+ LoginVO searchId(LoginVO vo);
+
+ /**
+ * 비밀번호를 찾는다.
+ * @param vo LoginVO
+ * @return LoginVO
+ * @exception Exception
+ */
+ LoginVO searchPassword(LoginVO vo);
+
+ /**
+ * 변경된 비밀번호를 저장한다.
+ * @param vo LoginVO
+ * @exception Exception
+ */
+ void updatePassword(LoginVO vo);
+}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/EgovLoginService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/EgovLoginService.java
new file mode 100644
index 0000000..44bac61
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/EgovLoginService.java
@@ -0,0 +1,52 @@
+package com.dbnt.kcscbackend.auth.service;
+
+
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
+
+/**
+ * 일반 로그인을 처리하는 비즈니스 구현 클래스
+ * @author 공통서비스 개발팀 박지욱
+ * @since 2009.03.06
+ * @version 1.0
+ * @see
+ *
+ *
+ * << 개정이력(Modification Information) >>
+ *
+ * 수정일 수정자 수정내용
+ * ------- -------- ---------------------------
+ * 2009.03.06 박지욱 최초 생성
+ * 2011.08.31 JJY 경량환경 템플릿 커스터마이징버전 생성
+ *
+ *
+ */
+public interface EgovLoginService {
+
+ /**
+ * 일반 로그인을 처리한다
+ * @return LoginVO
+ *
+ * @param vo LoginVO
+ * @exception Exception Exception
+ */
+ public LoginVO actionLogin(LoginVO vo) throws Exception;
+
+ /**
+ * 아이디를 찾는다.
+ * @return LoginVO
+ *
+ * @param vo LoginVO
+ * @exception Exception Exception
+ */
+ public LoginVO searchId(LoginVO vo) throws Exception;
+
+ /**
+ * 비밀번호를 찾는다.
+ * @return boolean
+ *
+ * @param vo LoginVO
+ * @exception Exception Exception
+ */
+ public boolean searchPassword(LoginVO vo) throws Exception;
+
+}
\ No newline at end of file
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java
new file mode 100644
index 0000000..ad5941f
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java
@@ -0,0 +1,125 @@
+package com.dbnt.kcscbackend.auth.service.impl;
+
+import com.dbnt.kcscbackend.auth.mapper.LoginUserMapper;
+import com.dbnt.kcscbackend.auth.service.EgovLoginService;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
+import com.dbnt.kcscbackend.config.egov.EgovFileScrty;
+import com.dbnt.kcscbackend.config.util.EgovNumberUtil;
+import com.dbnt.kcscbackend.config.util.EgovStringUtil;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 일반 로그인을 처리하는 비즈니스 구현 클래스
+ * @author 공통서비스 개발팀 박지욱
+ * @since 2009.03.06
+ * @version 1.0
+ * @see
+ *
+ *
+ * << 개정이력(Modification Information) >>
+ *
+ * 수정일 수정자 수정내용
+ * ------- -------- ---------------------------
+ * 2009.03.06 박지욱 최초 생성
+ * 2011.08.31 JJY 경량환경 템플릿 커스터마이징버전 생성
+ *
+ *
+ */
+@Service
+@Transactional
+@RequiredArgsConstructor
+public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements EgovLoginService {
+
+ private final LoginUserMapper loginMapper;
+
+ /**
+ * 일반 로그인을 처리한다
+ * @param vo LoginVO
+ * @return LoginVO
+ * @exception Exception
+ */
+ @Override
+ public LoginVO actionLogin(LoginVO vo) throws Exception {
+
+ // 1. 입력한 비밀번호를 암호화한다.
+ String enpassword = EgovFileScrty.encryptPassword(vo.getPassword(), vo.getId());
+ vo.setPassword(enpassword);
+
+ // 2. 아이디와 암호화된 비밀번호가 DB와 일치하는지 확인한다.
+ LoginVO loginVO = loginMapper.actionLogin(vo);
+
+ // 3. 결과를 리턴한다.
+ if (loginVO != null && !loginVO.getId().equals("") && !loginVO.getPassword().equals("")) {
+ return loginVO;
+ } else {
+ loginVO = new LoginVO();
+ }
+
+ return loginVO;
+ }
+
+ /**
+ * 아이디를 찾는다.
+ * @param vo LoginVO
+ * @return LoginVO
+ * @exception Exception
+ */
+ @Override
+ public LoginVO searchId(LoginVO vo) throws Exception {
+
+ // 1. 이름, 이메일주소가 DB와 일치하는 사용자 ID를 조회한다.
+ LoginVO loginVO = loginMapper.searchId(vo);
+
+ // 2. 결과를 리턴한다.
+ if (loginVO != null && !loginVO.getId().equals("")) {
+ return loginVO;
+ } else {
+ loginVO = new LoginVO();
+ }
+
+ return loginVO;
+ }
+
+ /**
+ * 비밀번호를 찾는다.
+ * @param vo LoginVO
+ * @return boolean
+ * @exception Exception
+ */
+ @Override
+ public boolean searchPassword(LoginVO vo) throws Exception {
+
+ boolean result = true;
+
+ // 1. 아이디, 이름, 이메일주소, 비밀번호 힌트, 비밀번호 정답이 DB와 일치하는 사용자 Password를 조회한다.
+ LoginVO loginVO = loginMapper.searchPassword(vo);
+ if (loginVO == null || loginVO.getPassword() == null || loginVO.getPassword().equals("")) {
+ return false;
+ }
+
+ // 2. 임시 비밀번호를 생성한다.(영+영+숫+영+영+숫=6자리)
+ String newpassword = "";
+ for (int i = 1; i <= 6; i++) {
+ // 영자
+ if (i % 3 != 0) {
+ newpassword += EgovStringUtil.getRandomStr('a', 'z');
+ // 숫자
+ } else {
+ newpassword += EgovNumberUtil.getRandomNum(0, 9);
+ }
+ }
+
+ // 3. 임시 비밀번호를 암호화하여 DB에 저장한다.
+ LoginVO pwVO = new LoginVO();
+ String enpassword = EgovFileScrty.encryptPassword(newpassword, vo.getId());
+ pwVO.setId(vo.getId());
+ pwVO.setPassword(enpassword);
+ pwVO.setUserSe(vo.getUserSe());
+ loginMapper.updatePassword(pwVO);
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/egov/EgovFileScrty.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/egov/EgovFileScrty.java
new file mode 100644
index 0000000..98f3c43
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/egov/EgovFileScrty.java
@@ -0,0 +1,305 @@
+package com.dbnt.kcscbackend.config.egov;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import java.io.*;
+import java.security.MessageDigest;
+
+/**
+ * Base64인코딩/디코딩 방식을 이용한 데이터를 암호화/복호화하는 Business Interface class
+ * @author 공통서비스개발팀 박지욱
+ * @since 2009.01.19
+ * @version 1.0
+ * @see
+ *
+ *
+ * << 개정이력(Modification Information) >>
+ *
+ * 수정일 수정자 수정내용
+ * ------- -------- ---------------------------
+ * 2009.01.19 박지욱 최초 생성
+ * 2011.08.31 JJY 경량환경 템플릿 커스터마이징버전 생성
+ *
+ *
+ */
+@Slf4j
+public class EgovFileScrty {
+ // 파일구분자
+ static final String FILE_SEPARATOR = System.getProperty("file.separator");
+ // 버퍼사이즈
+ static final int BUFFER_SIZE = 1024;
+
+ /**
+ * 파일을 암호화하는 기능
+ *
+ * @param source 암호화할 파일
+ * @param target 암호화된 파일
+ * @return boolean result 암호화여부 True/False
+ * @exception Exception
+ */
+ public static boolean encryptFile(String source, String target) throws Exception {
+
+ // 암호화 여부
+ boolean result = false;
+
+ String sourceFile = EgovWebUtil.filePathBlackList(source.replace("\\", FILE_SEPARATOR).replace("/", FILE_SEPARATOR));
+ String targetFile = EgovWebUtil.filePathBlackList(target.replace("\\", FILE_SEPARATOR).replace("/", FILE_SEPARATOR));
+ File srcFile = new File(sourceFile);
+
+ BufferedInputStream input = null;
+ BufferedOutputStream output = null;
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ try {
+ if (srcFile.exists() && srcFile.isFile()) {
+
+ input = new BufferedInputStream(new FileInputStream(srcFile));
+ output = new BufferedOutputStream(new FileOutputStream(targetFile));
+
+ int length = 0;
+ while ((length = input.read(buffer)) >= 0) {
+ byte[] data = new byte[length];
+ System.arraycopy(buffer, 0, data, 0, length);
+ output.write(encodeBinary(data).getBytes());
+ output.write(System.getProperty("line.separator").getBytes());
+ }
+
+ result = true;
+ }
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException ignore) {
+ log.debug("IGNORE: {}", ignore);
+ }
+ }
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException ignore) {
+ log.debug("IGNORE: {}", ignore);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 파일을 복호화하는 기능
+ *
+ * @param source 복호화할 파일
+ * @param target 복호화된 파일
+ * @return boolean result 복호화여부 True/False
+ * @exception Exception
+ */
+ public static boolean decryptFile(String source, String target) throws Exception {
+
+ // 복호화 여부
+ boolean result = false;
+
+ String sourceFile = source.replace("\\", FILE_SEPARATOR).replace("/", FILE_SEPARATOR);
+ String targetFile = target.replace("\\", FILE_SEPARATOR).replace("/", FILE_SEPARATOR);
+ File srcFile = new File(sourceFile);
+
+ BufferedReader input = null;
+ BufferedOutputStream output = null;
+
+ //byte[] buffer = new byte[BUFFER_SIZE];
+ String line = null;
+
+ try {
+ if (srcFile.exists() && srcFile.isFile()) {
+
+ input = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile)));
+ output = new BufferedOutputStream(new FileOutputStream(targetFile));
+
+ while ((line = input.readLine()) != null) {
+ byte[] data = line.getBytes();
+ output.write(decodeBinary(new String(data)));
+ }
+
+ result = true;
+ }
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException ignore) {
+ log.debug("IGNORE: {}", ignore);
+ }
+ }
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException ignore) {
+ log.debug("IGNORE: {}", ignore);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 데이터를 암호화하는 기능
+ *
+ * @param data 암호화할 데이터
+ * @return String result 암호화된 데이터
+ * @exception Exception
+ */
+ public static String encodeBinary(byte[] data) throws Exception {
+ if (data == null) {
+ return "";
+ }
+
+ return new String(Base64.encodeBase64(data));
+ }
+
+ /**
+ * 데이터를 암호화하는 기능
+ *
+ * @param data 암호화할 데이터
+ * @return String result 암호화된 데이터
+ * @exception Exception
+ */
+ public static String encode(String data) throws Exception {
+ return encodeBinary(data.getBytes());
+ }
+
+ /**
+ * 데이터를 복호화하는 기능
+ *
+ * @param data 복호화할 데이터
+ * @return String result 복호화된 데이터
+ * @exception Exception
+ */
+ public static byte[] decodeBinary(String data) throws Exception {
+ return Base64.decodeBase64(data.getBytes());
+ }
+
+ /**
+ * 데이터를 복호화하는 기능
+ *
+ * @param String data 복호화할 데이터
+ * @return String result 복호화된 데이터
+ * @exception Exception
+ */
+ public static String decode(String data) throws Exception {
+ return new String(decodeBinary(data));
+ }
+
+ /**
+ * 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용).
+ *
+ * deprecated : 보안 강화를 위하여 salt로 ID를 지정하는 encryptPassword(password, id) 사용
+ *
+ * @param data 암호화할 비밀번호
+ * @return String result 암호화된 비밀번호
+ * @exception Exception
+ */
+ @Deprecated
+ public static String encryptPassword(String data) throws Exception {
+
+ if (data == null) {
+ return "";
+ }
+
+ byte[] plainText = null; // 평문
+ byte[] hashValue = null; // 해쉬값
+ plainText = data.getBytes();
+
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ // 변경 시 기존 hash 값에 검증 불가.. => deprecated 시키고 유지
+ /*
+ // Random 방식의 salt 추가
+ SecureRandom ng = new SecureRandom();
+ byte[] randomBytes = new byte[16];
+ ng.nextBytes(randomBytes);
+
+ md.reset();
+ md.update(randomBytes);
+
+ */
+ hashValue = md.digest(plainText);
+
+ /*
+ BASE64Encoder encoder = new BASE64Encoder();
+ return encoder.encode(hashValue);
+ */
+ return new String(Base64.encodeBase64(hashValue));
+ }
+
+ /**
+ * 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용)
+ *
+ * @param password 암호화될 패스워드
+ * @param id salt로 사용될 사용자 ID 지정
+ * @return
+ * @throws Exception
+ */
+ public static String encryptPassword(String password, String id) throws Exception {
+
+ if (password == null) {
+ return "";
+ }
+
+ byte[] hashValue = null; // 해쉬값
+
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ md.reset();
+ md.update(id.getBytes());
+
+ hashValue = md.digest(password.getBytes());
+
+ return new String(Base64.encodeBase64(hashValue));
+ }
+
+ /**
+ * 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용)
+ * @param data 암호화할 비밀번호
+ * @param salt Salt
+ * @return 암호화된 비밀번호
+ * @throws Exception
+ */
+ public static String encryptPassword(String data, byte[] salt) throws Exception {
+
+ if (data == null) {
+ return "";
+ }
+
+ byte[] hashValue = null; // 해쉬값
+
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ md.reset();
+ md.update(salt);
+
+ hashValue = md.digest(data.getBytes());
+
+ return new String(Base64.encodeBase64(hashValue));
+ }
+
+ /**
+ * 비밀번호를 암호화된 패스워드 검증(salt가 사용된 경우만 적용).
+ *
+ * @param data 원 패스워드
+ * @param encoded 해쉬처리된 패스워드(Base64 인코딩)
+ * @return
+ * @throws Exception
+ */
+ public static boolean checkPassword(String data, String encoded, byte[] salt) throws Exception {
+ byte[] hashValue = null; // 해쉬값
+
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ md.reset();
+ md.update(salt);
+ hashValue = md.digest(data.getBytes());
+
+ return MessageDigest.isEqual(hashValue, Base64.decodeBase64(encoded.getBytes()));
+ }
+}
\ No newline at end of file
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java
index f69a140..83c58c0 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/EgovJwtTokenUtil.java
@@ -2,7 +2,7 @@ package com.dbnt.kcscbackend.config.jwt;
import com.dbnt.kcscbackend.config.egov.EgovProperties;
-import com.dbnt.kcscbackend.config.common.LoginVO;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
index 16ef3a5..1a830ee 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
@@ -1,6 +1,6 @@
package com.dbnt.kcscbackend.config.jwt;
-import com.dbnt.kcscbackend.config.common.LoginVO;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
import com.dbnt.kcscbackend.config.util.EgovStringUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomAuthenticationPrincipalResolver.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomAuthenticationPrincipalResolver.java
index 733e86e..e57d0c5 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomAuthenticationPrincipalResolver.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/CustomAuthenticationPrincipalResolver.java
@@ -1,6 +1,6 @@
package com.dbnt.kcscbackend.config.security;
-import com.dbnt.kcscbackend.config.common.LoginVO;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
import org.springframework.core.MethodParameter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java
index a7768fc..4a242fa 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/security/SecurityConfig.java
@@ -44,6 +44,7 @@ public class SecurityConfig {
"/login/**",
"/auth/login-jwt",//JWT 로그인
"/auth/login",//일반 로그인
+ "/auth/join",//회원가입
"/cmm/main/**.do", // 메인페이지
"/cmm/fms/FileDown.do", //파일 다운로드
"/cmm/fms/getImage.do", //갤러리 이미지보기
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
index 6e4ad43..63782da 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
@@ -1,7 +1,7 @@
package com.dbnt.kcscbackend.standardCode;
import com.dbnt.kcscbackend.config.common.BaseController;
-import com.dbnt.kcscbackend.config.common.LoginVO;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentCodeList;
diff --git a/kcsc-back-end/src/main/resources/mybatisMapper/LoginUserMapper.xml b/kcsc-back-end/src/main/resources/mybatisMapper/LoginUserMapper.xml
new file mode 100644
index 0000000..182a296
--- /dev/null
+++ b/kcsc-back-end/src/main/resources/mybatisMapper/LoginUserMapper.xml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UPDATE LETTNGNRLMBER
+ SET password = #{password}
+ WHERE mber_id = #{id}
+
+
+
+
+
+ UPDATE LETTNENTRPRSMBER
+ SET entrprs_mber_password = #{password}
+ WHERE entrprsmber_id = #{id}
+
+
+
+
+
+ UPDATE LETTNEMPLYRINFO
+ SET password = #{password}
+ WHERE emplyr_id = #{id}
+
+
+
+
\ No newline at end of file