diff --git a/data/dataxml/uac.service.board.qna_GET.xml b/data/dataxml/uac.service.board.qna_GET.xml index 3f926a39..2e5c2b22 100644 --- a/data/dataxml/uac.service.board.qna_GET.xml +++ b/data/dataxml/uac.service.board.qna_GET.xml @@ -6,7 +6,7 @@ 101 Q&A 공지사항 테스트 - 111 + 9uCh4qxBlFqap/+KiqoM68EqO8yYGpKa1c+BCgkOEa4= 15 2021-07-19 김아무 diff --git a/src/main/java/nlib/bbs/web/BoardController.java b/src/main/java/nlib/bbs/web/BoardController.java index bfa68499..f48f69d8 100644 --- a/src/main/java/nlib/bbs/web/BoardController.java +++ b/src/main/java/nlib/bbs/web/BoardController.java @@ -23,6 +23,7 @@ import nlib.bbs.service.BoardService; import nlib.cmm.NlibCommonController; import nlib.cmm.crypto.AriaCrypto; import nlib.cmm.crypto.NlibPasswordEncoder; +import nlib.cmm.exception.ErrorMessage; import nlib.cmm.service.CodeService; import nlib.cmm.service.NlibProperty; import nlib.restful.service.DataApiReqVO; @@ -180,7 +181,6 @@ public class BoardController extends NlibCommonController String pageSize = paramMap.get("pageSize"); String message = paramMap.get("message"); - // 게시물 번호 String articleNo = paramMap.get("articleNo"); @@ -197,24 +197,19 @@ public class BoardController extends NlibCommonController reqVO.setAuthKey(createAuthKey(req, authentication)); reqVO.setPageIndex(pageIndex); reqVO.setPageSize(pageSize); + reqVO.addInfoItem("boardNo", "QNA"); // 게시판ID + reqVO.addInfoItem("articleNo", articleNo); // 게시물번호 - // 추가 정보 설정 : 게시판ID, 게시물번호 - HashMap info = new HashMap(); - info.put("boardNo", "QNA"); - info.put("articleNo", articleNo); - reqVO.setInfo(info); - // 요청 DataApiResVO resVO = boardService.selectQnA(reqVO); // 반환 정보 model.addAttribute("articleNo" , articleNo); - model.addAttribute("article" , resVO.getInfo()); - model.addAttribute("preArticle" , resVO.getList().get(0)); - model.addAttribute("nextArticle" , resVO.getList().get(1)); + model.addAttribute("article" , resVO.getInfo()); // 게시물 상세 + model.addAttribute("preArticle" , resVO.getList().get(0)); // 이전글 정보 + model.addAttribute("nextArticle" , resVO.getList().get(1)); // 다음글 정보 model.addAttribute("message" , message); - - model.addAttribute("pageIndex" , pageIndex); + model.addAttribute("pageIndex" , pageIndex); model.addAttribute("pageSize" , pageSize); model.addAttribute("searchKeyword", searchKeyword); @@ -305,20 +300,19 @@ public class BoardController extends NlibCommonController reqVO.setAuthKey(createAuthKey(req, authentication)); reqVO.setPageIndex(pageIndex); reqVO.setPageSize(pageSize); + reqVO.addInfoItem("boardNo", "QNA"); // 게시판ID + reqVO.addInfoItem("articleNo", articleNo); // 게시물번호 - // 추가 정보 설정 : 게시판ID, 게시물번호 - HashMap info = new HashMap(); - info.put("boardNo", "QNA"); - info.put("articleNo", articleNo); - reqVO.setInfo(info); - // 요청 DataApiResVO resVO = boardService.selectQnA(reqVO); // 비밀번호 확인 HashMap article = resVO.getInfo(); - if(!articlePassword.equals(article.get("articlePassword"))) { - model.addAttribute("message", "비밀빈호가 올바르지 않습니다.(1)"); + String shaArticlePassword = nlibPasswordEncoder.encode(articlePassword); + log.debug("updateQnAForm > 입력받은 비밀번호를 SHA256 암호화한 값 : " + shaArticlePassword); + + if(!shaArticlePassword.equals(article.get("articlePassword"))) { + model.addAttribute("message", "비밀번호가 올바르지 않습니다.(1)"); return "redirect:/board/selectQnA.do"; } @@ -326,13 +320,16 @@ public class BoardController extends NlibCommonController model.addAttribute("articleNo" , articleNo); model.addAttribute("article" , resVO.getInfo()); + //------------------------------- // 게시글 비밀번호 처리 - String shaArticlePassword = nlibPasswordEncoder.encode(articlePassword); - String encArticlePassword = ariaCrypto.encode(shaArticlePassword, createAuthKey(req, authentication)); + //------------------------------- + // 비밀번호 : SHA-256 암호화 처리되어 DB에 저장되며, + // 웹 화면에 표출될 때는 Aria로 articleNo를 Salt값으로 하여 재암호화처리하고 BASE64로 다시 한번 인코딩하여 표출함 + String encArticlePassword = StringUtil.encodeBase64(ariaCrypto.encode(shaArticlePassword, articleNo)); model.addAttribute("encArticlePassword", encArticlePassword); // 검색 정보 - model.addAttribute("pageIndex" , pageIndex); + model.addAttribute("pageIndex" , pageIndex); model.addAttribute("pageSize" , pageSize); model.addAttribute("searchKeyword", searchKeyword); @@ -354,8 +351,15 @@ public class BoardController extends NlibCommonController // 게시물 번호 String articleNo = paramMap.get("articleNo"); + + //------------------------------- + // 게시글 비밀번호 처리 + //------------------------------- + // 비밀번호 : SHA-256 암호화 처리되어 DB에 저장되며, + // 웹 화면에 표출될 때는 Aria로 articleNo를 Salt값으로 하여 재암호화처리하고 BASE64로 다시 한번 인코딩하여 표출함 String encArticlePassword = paramMap.get("encArticlePassword"); - String checkArticlePassword = ariaCrypto.decode(encArticlePassword, authKey); + String checkArticlePassword = ariaCrypto.decode(StringUtil.decodeBase64(encArticlePassword), articleNo); + String articlePassword = paramMap.get("articlePassword"); //------------------------------- // 비밀번호 유효 체크 @@ -368,11 +372,20 @@ public class BoardController extends NlibCommonController DataApiResVO resVO = boardService.selectQnA(reqVO); String oldArticlePassword = resVO.getInfoItem("articlePassword"); if(checkArticlePassword == null || !checkArticlePassword.equals(oldArticlePassword)) { - message = "잘못된 접근입니다."; - // TODO 수정화면으로 다시 redirect 시킬것 - return "redirect:/board/updateQnAForm.do"; + model.addAttribute("errorMessage", new ErrorMessage("ERR_BRD_UPDTQNA", "잘못된 접근입니다.")); + return "redirect:/alert/showError.do"; } + + // 새 글비밀번호가 존재하지 않는 경우, 기존 비밀번호 설정 처리 + if(StringUtil.isEmpty(articlePassword)) { + articlePassword = checkArticlePassword; + } + // 새 글비밀번호가 입력된 경우, SHA256 암호화 처리하여 설정 + else { + articlePassword = nlibPasswordEncoder.encode(articlePassword); + } + //------------------------------- // REQ VO 구성 //------------------------------- @@ -384,6 +397,7 @@ public class BoardController extends NlibCommonController updateReqVO.addInfoItem("regUserName" , paramMap.get("regUserName")); updateReqVO.addInfoItem("email" , paramMap.get("email")); updateReqVO.addInfoItem("contentQeust", paramMap.get("contentQeust")); + updateReqVO.addInfoItem("articlePassword", articlePassword); // SHA256 글비밀번호 // 요청 DataApiResVO updateResVO = boardService.updateQnA(updateReqVO); @@ -391,18 +405,19 @@ public class BoardController extends NlibCommonController // 처리결과 확인 if(!updateResVO.isSuccess()) { message = updateResVO.getResultMessage(); + addParamsToModel(paramMap, model); return "redirect:/board/updateQnAForm.do"; } // 반환 정보 model.addAttribute("articleNo" , updateResVO.getInfoItem("articleNo")); // 신규등록된 게시물 ID model.addAttribute("article" , resVO.getInfo()); + model.addAttribute("message" , "성공적으로 수정처리되었습니다."); // 검색 정보 model.addAttribute("pageIndex" , pageIndex); model.addAttribute("pageSize" , pageSize); model.addAttribute("searchKeyword", searchKeyword); - model.addAttribute("message" , ""); return "redirect:nlib/board/selectQnA"; } @@ -412,5 +427,4 @@ public class BoardController extends NlibCommonController return "nlib/board/deleteQnA"; } - } \ No newline at end of file diff --git a/src/main/java/nlib/cmm/NlibCommonController.java b/src/main/java/nlib/cmm/NlibCommonController.java index ae6b389e..c8de86f0 100644 --- a/src/main/java/nlib/cmm/NlibCommonController.java +++ b/src/main/java/nlib/cmm/NlibCommonController.java @@ -3,6 +3,7 @@ package nlib.cmm; import java.util.Base64; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -12,6 +13,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; +import org.springframework.ui.ModelMap; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -21,6 +23,7 @@ import nlib.cmm.exception.ErrorMessage; import nlib.restful.service.DataApiResVO; import nlib.security.SecUserVO; import nlib.user.service.NlibLoginVO; +import nlib.util.StringUtil; /** *
@@ -174,5 +177,22 @@ public class NlibCommonController {
 
 	    return ResponseEntity.ok().headers(headers).body(jsonStr);
 	}
+	
+	public ModelMap addParamsToModel(Map paramMap, ModelMap model) {
+		return addParamsToModel(paramMap, model, null, null);
+	}
+	public ModelMap addParamsToModel(Map paramMap, ModelMap model, String upperMapName, String itemNames) {
+		
+		if(paramMap == null || paramMap.size() < 1) return model;
+		if(model == null) return model;
+		
+		boolean existUpperMap = StringUtil.isNotEmpty(upperMapName);
+		Map uppperMap = new HashMap();
+		for(String key : paramMap.keySet()) {
+			model.addAttribute(key, paramMap.get(key));
+		}
+		
+		return model;
+	}
 
 }
diff --git a/src/main/java/nlib/cmm/exception/ErrorMessage.java b/src/main/java/nlib/cmm/exception/ErrorMessage.java
index 7488cce9..2899abd4 100644
--- a/src/main/java/nlib/cmm/exception/ErrorMessage.java
+++ b/src/main/java/nlib/cmm/exception/ErrorMessage.java
@@ -13,5 +13,21 @@ public class ErrorMessage {
 		this.code = code;
 		this.message = message;
 	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
 	
 }
diff --git a/src/main/java/nlib/cmm/web/AlertController.java b/src/main/java/nlib/cmm/web/AlertController.java
new file mode 100644
index 00000000..f2cf519a
--- /dev/null
+++ b/src/main/java/nlib/cmm/web/AlertController.java
@@ -0,0 +1,55 @@
+package nlib.cmm.web;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import nlib.cmm.exception.ErrorMessage;
+
+/**
+ * 
+ * @Class Name : AlertController.java
+ * 
+ * @Description : 각종 처리 결과/오류 안내관련 공통 컨트롤러 클래스 
+ * 
+ * 
+ * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
+ *
+ * 
+ * + * @ ------------ -------- --------------------------- + * @ 수정일 수정자 수정내용 + * @ ------------ -------- --------------------------- + * @ 2021. 7. 29. KNKIM 최초 생성 + * + * + * @author 이씨플라자 * DIGITALSHIP KNKIM + * @since 2021. 7. 29. + * @version 1.0 + * + */ +@Controller +public class AlertController { + + private static final Logger log = LoggerFactory.getLogger(SystemController.class); + + /** + * NLIB Property 재로드 작업을 요청한다. + * + * @param authentication + * @param model + * @return + */ + @RequestMapping( {"/alert/showError.do"} ) + public String showError(@RequestParam ErrorMessage errorMessage, ModelMap model) { + + model.addAttribute("code", errorMessage.getCode()); + model.addAttribute("message", errorMessage.getMessage()); + + return "nlib/cmm/common"; + } + +} \ No newline at end of file diff --git a/src/main/java/nlib/util/StringUtil.java b/src/main/java/nlib/util/StringUtil.java index 59f7d4d5..eaf66979 100644 --- a/src/main/java/nlib/util/StringUtil.java +++ b/src/main/java/nlib/util/StringUtil.java @@ -2,6 +2,9 @@ package nlib.util; import java.sql.Timestamp; import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.Base64.Encoder; import java.util.Locale; import egovframework.com.utl.fcc.service.EgovStringUtil; @@ -107,4 +110,31 @@ public class StringUtil extends EgovStringUtil { return rtnStr; } + + + /** + * Base64로 인코딩한다. + * + * @return + */ + public static String encodeBase64(String str) { + + if(str == null) return null; + + Encoder encoder = Base64.getEncoder(); + return new String(encoder.encode(str.getBytes())); + } + + /** + * Base64로 디코딩한다. + * + * @return + */ + public static String decodeBase64(String str) { + + if(str == null) return null; + + Decoder decoder = Base64.getDecoder(); + return new String(decoder.decode(str.getBytes())); + } } diff --git a/src/main/webapp/WEB-INF/jsp/nlib/board/updateQnAForm.jsp b/src/main/webapp/WEB-INF/jsp/nlib/board/updateQnAForm.jsp index 28e0562e..cf7f280b 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/board/updateQnAForm.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/board/updateQnAForm.jsp @@ -38,12 +38,7 @@ ${pageTitle} - - - - - - @@ -89,8 +78,9 @@ function fn_update() {
+ action="${pageContext.request.contextPath}/board/updateQnA.do" + method="post" + onsubmit="return fn_update();"> @@ -109,19 +99,21 @@ function fn_update() { 작성자 - + 이메일 - + 기존비밀번호 - 비밀번호 - + 비밀번호
(변경시 입력) +
+ * 비밀번호 : SHA-256 암호화 처리 후, DB에 저장되며, 웹 화면에 표출될 때는 Aria로 AuthKey를 Salt값으로 하여 재암호화처리하고 BASE64로 다시한번 인코딩하여 표출함 + 질문내용 @@ -131,10 +123,9 @@ function fn_update() {
- - + +
diff --git a/src/main/webapp/js/nlib.js b/src/main/webapp/js/nlib.js index 4a96ecbb..abb60e63 100644 --- a/src/main/webapp/js/nlib.js +++ b/src/main/webapp/js/nlib.js @@ -45,7 +45,25 @@ function fn_getIntValue(name, defaultValue) { } +const POPUP_DEFAULT_WIDTH = 600; // 팝업 기본 창 가로 크기 +const POPUP_DEFAULT_HEIGHT = 600; // 팝업 기본 창 세로 크기 + +/** + * 팝업을 생성하고 해당 URL로 접속한다. + * + * @param url + * @param popName + * @param width 생략 시 POPUP_DEFAULT_WIDTH + * @param height 생략 시 POPUP_DEFAULT_HEIGHT + * @returns + */ function openPopup(url, popName, width, height) { - var options = "top=10, left=10, width=" + (width?width:600) + ", height=" + (height?height:600) + ", status=no, menubar=no, toolbar=yes, resizable=no"; + var options = "top=10, left=10, width=" + (width?width:POPUP_DEFAULT_WIDTH) + ", height=" + (height?height:POPUP_DEFAULT_HEIGHT) + ", status=no, menubar=no, toolbar=yes, resizable=no"; window.open(url, popName, options); } + +function validEmail(email) { + if(!email) return false; + const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); +} \ No newline at end of file