개인정보 페이지 비밀번호 변경 기능 추가.
parent
c51c1649ad
commit
2f8fc492f8
|
|
@ -34,7 +34,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
http.authorizeRequests() // 페이지 권한 설정
|
http.authorizeRequests() // 페이지 권한 설정
|
||||||
.antMatchers("/board/**").hasRole(Role.USER.name()) // USER, ADMIN 접근 허용
|
.antMatchers("/board/**").hasRole(Role.USER.name()) // USER, ADMIN 접근 허용
|
||||||
.antMatchers("/info").hasRole(Role.USER.name()) // USER, ADMIN 접근 허용
|
.antMatchers("/info/**").hasRole(Role.USER.name()) // USER, ADMIN 접근 허용
|
||||||
.antMatchers("/admin/**").hasRole(Role.ADMIN.name()) // ADMIN만 접근 허용
|
.antMatchers("/admin/**").hasRole(Role.ADMIN.name()) // ADMIN만 접근 허용
|
||||||
.antMatchers("/user/login").permitAll() // 로그인 페이지는 권한 없이 접근 허용
|
.antMatchers("/user/login").permitAll() // 로그인 페이지는 권한 없이 접근 허용
|
||||||
.and() // 로그인 설정
|
.and() // 로그인 설정
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
package com.dbnt.kcgfilemanager.controller;
|
package com.dbnt.kcgfilemanager.controller;
|
||||||
|
|
||||||
import com.dbnt.kcgfilemanager.model.CategoryRole;
|
|
||||||
import com.dbnt.kcgfilemanager.model.UserInfo;
|
import com.dbnt.kcgfilemanager.model.UserInfo;
|
||||||
import com.dbnt.kcgfilemanager.service.BoardCategoryService;
|
import com.dbnt.kcgfilemanager.service.BoardCategoryService;
|
||||||
import com.dbnt.kcgfilemanager.service.CategoryRoleService;
|
|
||||||
import com.dbnt.kcgfilemanager.service.CommonCodeService;
|
import com.dbnt.kcgfilemanager.service.CommonCodeService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import java.security.Principal;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
@ -22,18 +17,17 @@ public class BaseController {
|
||||||
|
|
||||||
private final CommonCodeService commonCodeService;
|
private final CommonCodeService commonCodeService;
|
||||||
private final BoardCategoryService boardCategoryService;
|
private final BoardCategoryService boardCategoryService;
|
||||||
private final CategoryRoleService categoryRoleService;
|
|
||||||
|
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public ModelAndView loginCheck(Principal principal, HttpSession session) {
|
public ModelAndView loginCheck(@AuthenticationPrincipal UserInfo loginUser, HttpSession session) {
|
||||||
ModelAndView mav = null;
|
ModelAndView mav = null;
|
||||||
if(principal == null){
|
if(loginUser == null){
|
||||||
mav = new ModelAndView("redirect:/user/login");
|
mav = new ModelAndView("redirect:/user/login");
|
||||||
}else{
|
}else{
|
||||||
session.setAttribute("positionList", commonCodeService.selectCommonCodeValue("POSITION"));
|
session.setAttribute("positionList", commonCodeService.selectCommonCodeValue("POSITION"));
|
||||||
session.setAttribute("departmentList", commonCodeService.selectCommonCodeValue("DEPARTMENT"));
|
session.setAttribute("departmentList", commonCodeService.selectCommonCodeValue("DEPARTMENT"));
|
||||||
session.setAttribute("categoryList", boardCategoryService.selectBoardCategoryAll(null, 1));
|
session.setAttribute("categoryList", boardCategoryService.selectBoardCategoryAll(null, 1));
|
||||||
if(((UserInfo)((UsernamePasswordAuthenticationToken) principal).getPrincipal()).getUserRole().indexOf("ADMIN")>0){
|
if(loginUser.getUserRole().indexOf("ADMIN")>0){
|
||||||
mav = new ModelAndView("redirect:/admin/main");
|
mav = new ModelAndView("redirect:/admin/main");
|
||||||
}else{
|
}else{
|
||||||
mav = new ModelAndView("redirect:/board/main");
|
mav = new ModelAndView("redirect:/board/main");
|
||||||
|
|
@ -67,16 +61,4 @@ public class BaseController {
|
||||||
ModelAndView mav = new ModelAndView("login/denied");
|
ModelAndView mav = new ModelAndView("login/denied");
|
||||||
return mav;
|
return mav;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/info")
|
|
||||||
public ModelAndView goMyInfo(@AuthenticationPrincipal UserInfo loginUser) {
|
|
||||||
ModelAndView mav = new ModelAndView("user/myInfo");
|
|
||||||
mav.addObject("loginUser", loginUser);
|
|
||||||
if(!loginUser.getUserRole().contains("ADMIN")){
|
|
||||||
CategoryRole categoryRole = new CategoryRole();
|
|
||||||
categoryRole.setUserSeq(loginUser.getUserSeq());
|
|
||||||
mav.addObject("categorySeqList", categoryRoleService.selectCategorySeqListToUser(categoryRole));
|
|
||||||
}
|
|
||||||
return mav;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.dbnt.kcgfilemanager.controller;
|
||||||
|
|
||||||
|
import com.dbnt.kcgfilemanager.model.CategoryRole;
|
||||||
|
import com.dbnt.kcgfilemanager.model.UserInfo;
|
||||||
|
import com.dbnt.kcgfilemanager.service.CategoryRoleService;
|
||||||
|
import com.dbnt.kcgfilemanager.service.UserInfoService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/info")
|
||||||
|
public class InfoController {
|
||||||
|
|
||||||
|
private final CategoryRoleService categoryRoleService;
|
||||||
|
private final UserInfoService userInfoService;
|
||||||
|
|
||||||
|
@GetMapping("/myInfo")
|
||||||
|
public ModelAndView myInfo(@AuthenticationPrincipal UserInfo loginUser) {
|
||||||
|
ModelAndView mav = new ModelAndView("user/myInfo");
|
||||||
|
mav.addObject("loginUser", loginUser);
|
||||||
|
if(!loginUser.getUserRole().contains("ADMIN")){
|
||||||
|
CategoryRole categoryRole = new CategoryRole();
|
||||||
|
categoryRole.setUserSeq(loginUser.getUserSeq());
|
||||||
|
mav.addObject("categorySeqList", categoryRoleService.selectCategorySeqListToUser(categoryRole));
|
||||||
|
}
|
||||||
|
return mav;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/passwordModify")
|
||||||
|
public String passwordModify(@AuthenticationPrincipal UserInfo loginUser, UserInfo modifyInfo){
|
||||||
|
return userInfoService.updatePassword(loginUser, modifyInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -44,6 +44,8 @@ public class UserInfo extends BaseModel implements UserDetails{
|
||||||
@Column(name = "USER_STATUS")
|
@Column(name = "USER_STATUS")
|
||||||
private String userStatus;
|
private String userStatus;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private String modifyPassword;
|
||||||
@Transient
|
@Transient
|
||||||
private String positionName;
|
private String positionName;
|
||||||
@Transient
|
@Transient
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,17 @@ public class UserInfoService implements UserDetailsService {
|
||||||
return targetUserInfo.getUserId();
|
return targetUserInfo.getUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String updatePassword(UserInfo loginUser, UserInfo modifyInfo){
|
||||||
|
Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
|
||||||
|
if(passwordEncoder.matches(modifyInfo.getPassword(), loginUser.getPassword())){
|
||||||
|
loginUser.setPassword(convertPassword(modifyInfo.getModifyPassword()));
|
||||||
|
userInfoRepository.save(loginUser);
|
||||||
|
return "OK";
|
||||||
|
}else{
|
||||||
|
return "passwordNotMatch";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String convertPassword(String password){
|
private String convertPassword(String password){
|
||||||
Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
|
Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
|
||||||
return passwordEncoder.encode(password);
|
return passwordEncoder.encode(password);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,62 @@ $(document).on('click', '#moveRightBtn', function (){
|
||||||
$(document).on('click', '#moveLeftBtn', function (){
|
$(document).on('click', '#moveLeftBtn', function (){
|
||||||
moveCategorySelectBody(-1);
|
moveCategorySelectBody(-1);
|
||||||
})
|
})
|
||||||
|
$(document).on('click', '#savePasswordBtn', function (){
|
||||||
|
if(passwordCheck()){
|
||||||
|
const formData = new FormData($("#modifyPasswordForm")[0]);
|
||||||
|
$.ajax({
|
||||||
|
type : 'PUT',
|
||||||
|
data : formData,
|
||||||
|
url : "/info/passwordModify",
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success : function(result) {
|
||||||
|
if(result==="OK"){
|
||||||
|
alert("수정되었습니다.");
|
||||||
|
$("#passwordModifyModal").find(".btn-close").click();
|
||||||
|
}else if(result==="passwordNotMatch"){
|
||||||
|
alert("현재 비밀번호가 맞지 않습니다.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error : function(xhr, status) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function passwordCheck(){
|
||||||
|
let returnFlag = true;
|
||||||
|
const password = $("#password");
|
||||||
|
const modifyPassword =$("#modifyPassword");
|
||||||
|
const passwordConfirm = $("#passwordConfirm");
|
||||||
|
if(!password.val()){
|
||||||
|
alert("비밀번호를 입력해주세요.");
|
||||||
|
returnFlag = false;
|
||||||
|
}
|
||||||
|
if(!modifyPassword.val()){
|
||||||
|
alert("새 비밀번호를 입력해주세요.");
|
||||||
|
returnFlag = false;
|
||||||
|
}
|
||||||
|
if(!passwordConfirm.val()){
|
||||||
|
alert("비밀번호 확인을 입력해주세요.");
|
||||||
|
returnFlag = false;
|
||||||
|
}
|
||||||
|
if(returnFlag){
|
||||||
|
const passwordReg = /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+]).{8,16}$/;
|
||||||
|
if(!passwordReg.test(modifyPassword.val())){
|
||||||
|
alert("비밀번호 조건이 맞지 않습니다.")
|
||||||
|
returnFlag = false;
|
||||||
|
}else{
|
||||||
|
if(modifyPassword.val() !== passwordConfirm.val()){
|
||||||
|
alert("비밀번호가 같지 않습니다.");
|
||||||
|
returnFlag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnFlag;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function moveCategorySelectBody(direction){
|
function moveCategorySelectBody(direction){
|
||||||
const categorySelectBody = $("#categorySelectBody");
|
const categorySelectBody = $("#categorySelectBody");
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||||
<div class="p-3">
|
<div class="p-3">
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
<div class="col-auto"><button type="button" class="btn btn-warning" id="moveLeftBtn"><i class="bi bi-arrow-left"></i></button></div>
|
<div class="col-auto"><button type="button" class="btn btn-info" id="moveLeftBtn"><i class="bi bi-arrow-left"></i></button></div>
|
||||||
<div class="col-auto"><button type="button" class="btn btn-warning" id="moveRightBtn"><i class="bi bi-arrow-right"></i></button></div>
|
<div class="col-auto"><button type="button" class="btn btn-info" id="moveRightBtn"><i class="bi bi-arrow-right"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row overflow-auto flex-nowrap" id="categorySelectBody">
|
<div class="row overflow-auto flex-nowrap" id="categorySelectBody">
|
||||||
<th:block th:each="depth1:${session.categoryList}">
|
<th:block th:each="depth1:${session.categoryList}">
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<!--<span class="fs-4">해양경찰청 파일관리 시스템</span>-->
|
<!--<span class="fs-4">해양경찰청 파일관리 시스템</span>-->
|
||||||
</a>
|
</a>
|
||||||
<ul class="nav nav-pills" sec:authorize="isAuthenticated()">
|
<ul class="nav nav-pills" sec:authorize="isAuthenticated()">
|
||||||
<li class="nav-item"><a href="/info" class="nav-link">개인정보</a></li>
|
<li class="nav-item"><a href="/info/myInfo" class="nav-link">개인정보</a></li>
|
||||||
<li class="nav-item"><a href="/logout" class="nav-link">로그아웃</a></li>
|
<li class="nav-item"><a href="/logout" class="nav-link">로그아웃</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
<div class="col-auto"><h4>개인정보</h4></div>
|
<div class="col-auto"><h4>개인정보</h4></div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<th:block th:if="${!#strings.contains(loginUser.userRole,'ADMIN')}">
|
<th:block th:if="${!#strings.contains(loginUser.userRole,'ADMIN')}">
|
||||||
<button class="btn btn-success"> 요청 현황</button>
|
<button class="btn btn-success mb-2"> 요청 현황</button>
|
||||||
<button class="btn btn-warning"> 수정 요청</button>
|
<button class="btn btn-warning mb-2"> 수정 요청</button>
|
||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -70,19 +70,24 @@
|
||||||
<input type="text" readonly class="form-control-plaintext" id="createDate" th:value="${#temporals.format(loginUser.createDate, 'yyyy-MM-dd')}">
|
<input type="text" readonly class="form-control-plaintext" id="createDate" th:value="${#temporals.format(loginUser.createDate, 'yyyy-MM-dd')}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3 row justify-content-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<button class="btn btn-warning" id="passwordModifyBtn" data-bs-toggle="modal" data-bs-target="#passwordModifyModal">비밀번호 변경</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<th:block th:if="${!#strings.contains(loginUser.userRole,'ADMIN')}">
|
<th:block th:if="${!#strings.contains(loginUser.userRole,'ADMIN')}">
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<h5 class="ps-3">권한정보</h5>
|
<h5 class="ps-3">작성 권한</h5>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="p-3">
|
<div class="p-3">
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
<div class="col-auto"><button type="button" class="btn btn-warning" id="moveLeftBtn"><i class="bi bi-arrow-left"></i></button></div>
|
<div class="col-auto"><button type="button" class="btn btn-info" id="moveLeftBtn"><i class="bi bi-arrow-left"></i></button></div>
|
||||||
<div class="col-auto"><button type="button" class="btn btn-warning" id="moveRightBtn"><i class="bi bi-arrow-right"></i></button></div>
|
<div class="col-auto"><button type="button" class="btn btn-info" id="moveRightBtn"><i class="bi bi-arrow-right"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row overflow-auto flex-nowrap" id="categorySelectBody">
|
<div class="row overflow-auto flex-nowrap" id="categorySelectBody">
|
||||||
<th:block th:each="depth1:${session.categoryList}">
|
<th:block th:each="depth1:${session.categoryList}">
|
||||||
|
|
@ -110,27 +115,6 @@
|
||||||
</th:block>
|
</th:block>
|
||||||
</th:block>
|
</th:block>
|
||||||
</th:block>
|
</th:block>
|
||||||
<!--<th:block th:each="depth2:${depth1.childCategoryList}">
|
|
||||||
<tr th:classappend="${#lists.contains(categorySeqList, depth2.categorySeq)}?'bg-success bg-opacity-25':''">
|
|
||||||
<td th:text="${depth2.categoryName}"></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<th:block th:each="depth3:${depth2.childCategoryList}">
|
|
||||||
<tr th:classappend="${#lists.contains(categorySeqList, depth3.categorySeq)}?'bg-success bg-opacity-25':''">
|
|
||||||
<td></td>
|
|
||||||
<td th:text="${depth3.categoryName}"></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<th:block th:each="depth4:${depth3.childCategoryList}">
|
|
||||||
<tr th:classappend="${#lists.contains(categorySeqList, depth4.categorySeq)}?'bg-success bg-opacity-25':''">
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td th:text="${depth4.categoryName}"></td>
|
|
||||||
</tr>
|
|
||||||
</th:block>
|
|
||||||
</th:block>
|
|
||||||
</th:block>-->
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -146,5 +130,41 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
<div class="modal fade" id="passwordModifyModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="passwordModifyModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="passwordModifyModalLabel">비밀번호 변경</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body mx-4">
|
||||||
|
<form th:action="@{/info/passwordModify}" method="post" id="modifyPasswordForm">
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="password" class="col-sm-4 col-form-label text-end">현재 비밀번호</label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<input type="password" class="form-control" id="password" name="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="modifyPassword" class="col-sm-4 col-form-label text-end">새 비밀번호</label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<input type="password" class="form-control" id="modifyPassword" name="modifyPassword">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="passwordConfirm" class="col-sm-4 col-form-label text-end">새 비밀번호 확인</label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<input type="password" class="form-control" id="passwordConfirm">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="savePasswordBtn">저장</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue