관리 메뉴

거니의 velog

231213_SPRING 2 (16-1) 본문

대덕인재개발원/대덕인재개발원_웹기반 애플리케이션

231213_SPRING 2 (16-1)

Unlimited00 2023. 12. 12. 16:19

package kr.or.ddit.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {

	private static final Logger log = LoggerFactory.getLogger(CustomLoginSuccessHandler.class);
	private RequestCache requestCache = new HttpSessionRequestCache();

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {

		log.info("onAuthenticationSuccess() 실행...!");
		
		User user = (User) authentication.getPrincipal();
		log.info("username : " + user.getUsername());
		log.info("password : " + user.getPassword());
		
		clearAuthenticationAttribute(request);
		
		SavedRequest savedRequest = requestCache.getRequest(request, response);
		String targetUrl = "";
		if(savedRequest != null) {
			targetUrl = savedRequest.getRedirectUrl();
		}else {
			targetUrl = "/notice/list.do";
		}
		
		log.info("Login Success targetUrl : " + targetUrl);
		response.sendRedirect(targetUrl);
		
	}

	private void clearAuthenticationAttribute(HttpServletRequest request) {
		// session 가 존재한다면 현재 session을 반환하고, 그렇지 않으면 null을 반환한다.
		HttpSession session = request.getSession(false);
		if(session == null) {
			return;
		}
		
		// SPRING_SECURITY_LAST_EXCEPTION 값을 세션에서 삭제
		session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
	}
	
}


<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<form class="input-group input-group-sm" method="post" style="width: 440px;" id="searchForm" name="searchForm">
    <input type="hidden" name="page" id="page" />
    <select class="form-control" name="searchType">
        <option value="title" <c:if test="${searchType eq 'title' }">selected</c:if>>제목</option>
        <option value="writer" <c:if test="${searchType eq 'writer' }">selected</c:if>>작성자</option>
    </select> 
    <input type="text" name="searchWord" value="${searchWord }" class="form-control float-right" placeholder="Search">
    <div class="input-group-append">
        <button type="submit" class="btn btn-default">
            <i class="fas fa-search"></i>검색
        </button>
    </div>
    <sec:csrfInput />
</form>

검색 기능 활성화


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
	                <sec:csrfInput/>
                </form>
<script>
	$(function(){
		CKEDITOR.replace("boContent", {
			filebrowserUploadUrl: '/imageUpload.do?${_csrf.parameterName}=${_csrf.token}'
		});
		CKEDITOR.config.height = "500px"; // CKEDITOR 높이 설정

현재 세션을 스프링 시큐리티에서 제작된 것으로 가용하고 있지 않기 때문에 생기는 오류...


package kr.or.ddit.controller.crud.notice;

import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.CustomUser;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import kr.or.ddit.vo.crud.NoticeVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeInsertController {
	
	@Inject
	private INoticeService noticeService;

	@RequestMapping(value = "/form.do", method = RequestMethod.GET)
	public String noticeInsertForm() {
		return "notice/form";
	}
	
	@RequestMapping(value = "/insert.do", method = RequestMethod.POST)
	public String noticeInsert(
			HttpServletRequest req,
			NoticeVO noticeVO, 
			Model model, 
			RedirectAttributes ra
			) {
		String goPage = "";
		
		// 넘겨받은 데이터 검증 후, 에러가 발생한 데이터에 대한 에러정보를 담을 공간
		Map<String, String> errors = new HashMap<String, String>();
		
		// 라이브러리 추가해야 함.
		// 제목 데이터가 누락되었을 때 에러 정보 저장
		if(StringUtils.isBlank(noticeVO.getBoTitle())) {
			errors.put("boTitle", "제목을 입력해주세요.");
		}
		// 내용 데이터가 누락되었을 때 에러 정보 저장
		if(StringUtils.isBlank(noticeVO.getBoContent())) {
			errors.put("boContent", "내용을 입력해주세요.");
		}
		// 기본 데이터의 누락정보에 따른 에러정보 갯수로 분기 처리
		if(errors.size() > 0) { // 에러 갯수가 0보다 클 때(에러가 존재)
			model.addAttribute("errors", errors);
			model.addAttribute("noticeVO", noticeVO);
			goPage = "notice/form";
		}else { // 에러가 없을 때
			
			// [HttpSession] 로그인 처리 후 세션 정보에서 얻어온 회원 정보를 가용하기 위한 준비
//			HttpSession session = req.getSession();
//			NoticeMemberVO memberVO = (NoticeMemberVO) session.getAttribute("SessionInfo");
			
			// [스프링 시큐리티] 회원 ID를 스프링 시큐리티 UserDetails 정보에서 가져오기
			CustomUser user = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
			NoticeMemberVO memberVO = user.getMember();
			
			// 세션 정보에서 꺼낸 회원 데이터가 null이 아닐 때(로그인을 진행)
			if(memberVO != null) {
				noticeVO.setBoWriter(memberVO.getMemId()); // 로그인된 회원 아이디를 작성자로 집어 넣기
				
				ServiceResult result = noticeService.insertNotice(req, noticeVO);
				if(result.equals(ServiceResult.OK)) {
					goPage = "redirect:/notice/detail.do?boNo=" + noticeVO.getBoNo();
					ra.addFlashAttribute("message", "게시글 등록이 완료되었습니다.");
				}else { // 등록 실패
					model.addAttribute("noticeVO", noticeVO);
					model.addAttribute("message", "서버 에러, 다시 시도해 주세요!");
					goPage = "notice/form";
				}
			}else { // 로그인을 진행하지 않았을 때
				// [방법1] - 등록을 진행하지만, 로그인 후에 가능하다는 걸 알려주기 위한 프로세스일 때
//				model.addAttribute("message", "로그인 후에 사용 가능합니다!");
//				model.addAttribute("notice", noticeVO);
//				goPage = "notice/form";
				
				// [방법2] - 등록을 진행하기 위해서는 로그인을 필수로 진행해야 합니다. 라는 프로세스일 때
				ra.addFlashAttribute("message", "로그인 후에 사용 가능합니다!");
				goPage = "redirect:/notice/login.do";
			}
			
		}
		
		return goPage;
	}
	
}

파일 다운로드도 잘 된다.


게시글 수정도 잘 된다


삭제가 안 됨


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
                    <form action="/notice/delete.do" method="post" id="delForm">
                    	<input type="hidden" name="boNo" value="${notice.boNo }" />
                    	<sec:csrfInput/>
                    </form>

삭제가 잘 된다.


package kr.or.ddit.controller.crud.notice;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.CustomUser;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeProfileController {
	
	@Inject
	private INoticeService noticeService;
	
	@RequestMapping(value = "/profile.do", method = RequestMethod.GET)
	public String noticeProfile(
			HttpServletRequest req,
			RedirectAttributes ra,
			Model model
			) {
		
		String goPage = "";
		
		// [일반적인 방법] 세션을 활용
//		HttpSession session = req.getSession();
//		NoticeMemberVO sessionMember = (NoticeMemberVO) session.getAttribute("SessionInfo");
//		
//		if(sessionMember == null) {
//			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
//			return "redirect:/notice/login.do";
//		}
//		
//		NoticeMemberVO member = noticeService.selectMember(sessionMember.getMemId());
		
		// [스프링 시큐리티] 시큐리티 세션을 활용
		CustomUser user = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		NoticeMemberVO memberVO = user.getMember();
		NoticeMemberVO member = noticeService.selectMember(memberVO.getMemId());
		
		if(member != null) {
			model.addAttribute("member", member);
			goPage = "notice/profile";
		}else {
			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
			goPage = "redirect:/notice/login.do";
		}
		
		return goPage;
		
	}
	
	@RequestMapping(value = "/profileUpdate.do", method = RequestMethod.POST)
	public String noticeProfileUpdate(
			HttpServletRequest req,
			NoticeMemberVO memberVO,
			RedirectAttributes ra,
			Model model
			) {
		
		String goPage = "";
		
		ServiceResult result = noticeService.profileUpdate(req, memberVO);
		if(result.equals(ServiceResult.OK)) {
			ra.addFlashAttribute("message", "회원정보 수정이 완료되었습니다!");
			goPage = "redirect:/notice/profile.do";
		}else {
			model.addAttribute("message", "서버에러, 수정이 실패했습니다!");
			model.addAttribute("member", memberVO);
			goPage = "notice/profile";
		}
		
		return goPage;
		
	}
	
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
	                    <sec:csrfInput/>
                    </form>

- http://localhost/notice/profile.do

수정이 잘 됨


<div class="card-footer">
    <button type="button" id="listBtn" class="btn btn-secondary">목록</button>
    <sec:authentication property="principal.member" var="member" />
    <sec:authorize access="hasAnyRole('ROLE_MEMBER', 'ROLE_ADMIN')">
        <c:if test="${member.memId eq notice.boWriter or member.memId eq 'admin' }">
            <button type="button" id="updateBtn" class="btn btn-dark">수정</button>
            <button type="button" id="deleteBtn" class="btn btn-danger">삭제</button>
        </c:if>
    </sec:authorize>
</div>

- admin 계정 필요...

관리자 일 때...
c001 기준으로 자기글 아니면 수정/삭제 없음


@Override
	public ServiceResult profileUpdate(HttpServletRequest req, NoticeMemberVO memberVO) {
		ServiceResult result = null;
		
		// 프로필 이미지를 업로드 하기 위한 서버 경로(/resources/profile)
		String uploadPath = req.getServletContext().getRealPath("/resources/profile");
		File file = new File(uploadPath);
		if(!file.exists()) {
			file.mkdirs();
		}
		
		String profileImg = "";
		try {
			
			MultipartFile profileImgFile = memberVO.getImgFile();
			if(profileImgFile.getOriginalFilename() != null && !profileImgFile.getOriginalFilename().equals("")) {
				String fileName = UUID.randomUUID().toString();
				fileName += "_" + profileImgFile.getOriginalFilename();
				uploadPath += "/" + fileName;
				profileImgFile.transferTo(new File(uploadPath));
				profileImg = "/resources/profile/" + fileName;
			}
			
			memberVO.setMemProfileImg(profileImg);
			
			memberVO.setMemPw(pe.encode(memberVO.getMemPw()));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		int status = profileMapper.profileUpdate(memberVO);
		if(status > 0) { // 수정 성공
			result = ServiceResult.OK;
		}else { // 수정 실패
			result = ServiceResult.FAILED;
		}
		
		return result;
	}

자동 로그인도 잘 된다...


	@RequestMapping(value = "/logout.do", method = RequestMethod.GET)
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:/notice/login.do";
	}

로그아웃 처리가 잘 완료 되는 모습을 볼 수 있다.


SVN 수동 설치

'대덕인재개발원 > 대덕인재개발원_웹기반 애플리케이션' 카테고리의 다른 글

231216_SPRING CRUD 보강 2  (0) 2023.12.15
231216_SPRING CRUD 보강 1  (0) 2023.12.15
231212_SPRING 2 (15-2)  (0) 2023.12.12
231212_SPRING 2 (15-1)  (0) 2023.12.11
231211_SPRING 2 (14-1)  (0) 2023.12.11