본문 바로가기
Spring공부/4-스프링시큐리티

프로젝트(1)

by 으노으뇨 2021. 10. 21.
728x90
반응형
SMALL

기존 프로젝트에 그동안 공부했던 스프링 시큐리티를 접목하는 작업을 진행하도록 하겠다.

그전에 해당 기능은

-로그인과 회원 가입 페이지의 작성

- 기존 화면과 컨트롤러에 시큐리티 관련 내용 추가

- Ajax부분의 변경


로그인 페이지 처리

기존의 로그인화면은 정말 끔찍하다.. 어쩌면 스프링에서 기본으로 주는화면급이었다. 

똑같았다 그냥 그럼 조금 이쁘게 부트스트랩을 적용하고, 아까의 로그인의 화면의 태그라던가 id는 동일하게 설정한뒤 생성해보았다.

<%@ 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://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Bootstrap Admin Theme</title>
<!-- Bootstrap Core CSS -->
<link href="/resources/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

<!-- MetisMenu CSS -->
<link href="/resources/vendor/metisMenu/metisMenu.min.css" rel="stylesheet">

<!-- Custom CSS -->
<link href="/resources/dist/css/sb-admin-2.css" rel="stylesheet">

<!-- Custom Fonts -->
<link href="/resources/vendor/font-awesome/css/font-awesome.min.css"
	rel="stylesheet" type="text/css">
</head>
<body>

	<div class="container">
		<div class="row">
			<div class="col-md-4 col-md-offset-4">
				<div class="login-panel panel panel-default">
					<div class="panel-heading">
						<h3 class="panel-title">Please Sign In</h3>
					</div>
					<div class="panel-body">
						<form role="form" method='post' action="/login">
							<fieldset>
								<div class="form-group">
									<input class="form-control" placeholder="userid"
										name="username" type="text" autofocus>
								</div>
								<div class="form-group">
									<input class="form-control" placeholder="Password"
										name="password" type="password" value="">
								</div>
								<div class="checkbox">
									<label> <input name="remember-me" type="checkbox">Remember
										Me
									</label>
								</div>
								<!-- Change this to a button or input when using this as a form -->
								<a href="index.html" class="btn btn-lg btn-success btn-block">Login</a>
							</fieldset>
							<input type="hidden" name="${_csrf.parameterName}"
								value="${_csrf.token}" />
						</form>

					</div>
				</div>
			</div>
		</div>
	</div>
	<!-- jQuery -->
	<script src="/resources/vendor/jquery/jquery.min.js"></script>
	<!-- Bootstrap Core JavaScript -->
	<script src="/resources/vendor/bootstrap/js/bootstrap.min.js"></script>
	<!-- Metis Menu Plugin JavaScript -->
	<script src="/resources/vendor/metisMenu/metisMenu.min.js"></script>
	<!-- Custom Theme JavaScript -->
	<script src="/resources/dist/js/sb-admin-2.js"></script>
  <script>
  $(".btn-success").on("click", function(e){
    e.preventDefault();
    $("form").submit();
  });
  </script>
</body>
</html>

폼태그가 붙고, 거기에 컨테이너 div가 붙고 해서 뭔가 복잡해 보이는데

 

화면으로보면 크게 달라진것은 없다. 귀찮다면 그전의 화면을 계속사용해도 문제는 없다. 하지만 

  • JSTL이나 스프링 시큐리티의 태그를 사용할 수 있도록 선언해주어야한다!!!
  • <form>태그내의 input태그의 name속성을 시큐리티에 맞게 수정해야주어야한다. 반드시!!!!
  •  CSRF토큰 항목 추가
  • JavaScript를 통한 로그인전송 기능 구현

로그인이 정상적으로 이루어지는 지 확인하자

우린 지금 로그인 성공 후에 CustomLoginSuccessHandler를 이용해서 사용자의 권한에 따라서 이동하도록 했다.

스프링 시큐리티는 기본적인 로그인 후 처리를 SavedRequestAwareAuthnticationSuccessHandeler라는 클래스를

이용한다. 해당 클래스는 사용자가 원래 보려고 했던 페이지의 정보를 유지해서 로그인후에 다시 원했던 페이지로 

이동하는 방식이다.

SavedRequestAwareAuthnticationSuccessHandeler를 이용하는 설정은 기존에 XML에서 

authentication-success-handler-ref 속성을 삭제하고 관련 스프링 빈의 설정도 사용하지 않도록 한다.

게시물의 작성(/board/register)시 로그인 페이지로 이동하고, 로그인 후에 다시 게시물의 작성 페이지로 이동하는 방식을 적용해보겠다.

<!-- 	<bean id="customLoginSuccess" -->
<!-- 		class="org.study.security.CustomLoginSuccessHandler"></bean> -->
<!-- security http 태그부분에서
<security:form-login login-page="/customLogin"/> 
<!--로수정해줄것-->

해당 클래스를 제거한 모습


게시물 작성 시 스프링 시큐리티 처리

일반적인 경우, 게시물 리스트는 모든사람이 제약없이 사용가능하고, 읽는것도, 구론데 게시물작성시나 댓글시에는

로그인한 사용자에 한해서 처리된다. 

이것을 고려해 security-context.xml에 스프링 시큐리티 관련 설정을 추가하고, BoardController에 어노테이션을 통해 제어하도록 해야한다.

겟방식으로 들어오면

//	@GetMapping("/register")
//	public void register() {
//	}
	@GetMapping("/register")
	@PreAuthorize("isAuthenticated()")
	public void register() {
	}

기존의 등록을 주석처리하고 @PreAutherize를 추가해주었다.

포스트방식으로 들어오면

//	@PostMapping("/register")
//	public String register(BoardVO board, RedirectAttributes rttr) {
//		if (board.getAttachList() != null) {
//			board.getAttachList().forEach(attach -> log.info(attach));
//		}
//		service.register(board);
//		rttr.addFlashAttribute("result", board.getBno());
//		return "redirect:/board/list";
//	}
	@PostMapping("/register")
	@PreAuthorize("isAuthenticated()")
	public String register(BoardVO board, RedirectAttributes rttr) {
		log.info("==========================");
		log.info("register: " + board);
		if (board.getAttachList() != null) {
			board.getAttachList().forEach(attach -> log.info(attach));
		}
		log.info("==========================");
		service.register(board);
		rttr.addFlashAttribute("result", board.getBno());
		return "redirect:/board/list";
	}

@preAuthorize를 이용할 떄의 표현식은 isAuthenticated()로 어떠한 사용자든 로그인이 성공한 사용자만이 해당 기능을 사용할 수 있도록 처리한다.


게시물 작성 시 로그인한 사용자의 아이디 출력

게시물의 작성은 이제 작성자를 직접우리가 써서 작성되는것이아닌 작성자항목에는 현재 사용자의 아이디가 출력될수 있게한다.

register.jsp파일에서 작성자를 입력받는 태그에 <sec:authentication property="principal.username"/> 를 넣어주고

읽기전용인 readonly를 붙여 수정해주자

          <div class="form-group">
            <label>Writer</label> <input class="form-control" name='writer' 
                value='<sec:authentication property="principal.username"/>' readonly="readonly">
          </div>

그리고 로그인이 된 상태에서 글 작성을 해보자

정상적으로 로그인 사용자의 아이디가 출력되었다.

CSRF 토큰을 설정

스프링 시큐리티를 사용할 때 post방식의 전송은 반드시 CSRF토큰을 사용하도록 추가해야한다.

<form>태그 내에 CSRF토큰의 값을 히든타입으로 처리하여 추가하여 주자

   <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

게시물 조회와 로그인 처리

일반적인 경우라면 게시물의 조회는 그 자체의 로그인 여부에 관계없이 처리되지만, 게시물의 조회화면에서 

현재 로그인한 사용자만이 수정/삭제 작업을 할 수 있는 기능이 활성화 된다.

게시물 조회를 담당하는 get.jsp파일에

현재 게시물의 작성자와 현재 로그인한 사용자 정보를 비교해서 이를 처리할 수 있도록한다.

본인이 작성하면 수정버튼이 생성, 아니라면 생성해 있지않음

상단에는 시큐리티 태그를 넣어주자.

<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<!-- 				<button data-oper='modify' class="btn btn-default">Modify</button> -->
 <sec:authentication property="principal" var="pinfo"/>
        <sec:authorize access="isAuthenticated()">
        <c:if test="${pinfo.username eq board.writer}">
        <button data-oper='modify' class="btn btn-default">Modify</button>
        </c:if>
        </sec:authorize>

기존 수정버튼을 위와같이 수정했다. <c:if>태그를 이용해 만약 유저정보와 해당 작성자가 같다면 수정버튼이 있도록 한것이다.

그리고 조회화면에서 댓글 추가버튼도 동일하게 넣어주자.

<!-- 			<div class="panel-heading"> -->
<!-- 				<i class="fa fa-comments fa-fw"></i> Reply -->
<!-- 				<button id='addReplyBtn' class='btn btn-primary btn-xs pull-right'>New -->
<!-- 					Reply</button> -->
<!-- 			</div> -->
div class="panel-heading">
<i class="fa fa-comments fa-fw"></i> Reply
<sec:authorize access="isAuthenticated()">
<button id='addReplyBtn' class='btn btn-primary btn-xs pull-right'>New Reply</button>
</sec:authorize>
</div>

기존의 버튼도 위와같이 등록창은 로그인이 되어있다면! 나타나도록 했다.

게시물의 수정/삭제

개사물의 수정과 삭제는 브라우저에서는 로그인한 사용자만이 접글 할 수 있지만, 사용자가 URL을 조작해서 접근이 가능하다.

그래서 화면과 POST방식으로 처리되는 부분에 CSRF토큰과 스프링 시큐리티를 적용해주자!

수정기능을 하는 modify.jsp 파일을 수정해야한다.

<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>

먼저 태그를 넣어주고,

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

토큰을 히든타입에 넣어준다.

조회와 마찬가지로 현재 로그인한 사용자가 게시물의 작성자인 경우에만 수정과 삭제가 가능하도록 제어한다.

<!-- 		<button type="submit" data-oper='modify' class="btn btn-default">Modify</button> -->
<!-- 		<button type="submit" data-oper='remove' class="btn btn-danger">Remove</button> -->
<sec:authentication property="principal" var="pinfo"/>
<sec:authorize access="isAuthenticated()">
<c:if test="${pinfo.username eq board.writer}">
  <button type="submit" data-oper='modify' class="btn btn-default">Modify</button>
  <button type="submit" data-oper='remove' class="btn btn-danger">Remove</button>
</c:if>
</sec:authorize>

기존의 버튼태그들은 주석처리하고 로그인상태와 해당 작성자가 같은 조건일경우 버튼이 나타나도록 했다.

이제 컨트롤단에서 해당 기능이 수정,삭제 될 수 있도록 수정해준다.

//	@PostMapping("/remove")
//	public String remove(@RequestParam("bno") Long bno, Criteria cri, RedirectAttributes rttr) {
//		List<BoardAttachVO> attachList = service.getAttachList(bno);
//		if (service.remove(bno)) {
//			deleteFiles(attachList);
//			rttr.addFlashAttribute("result", "success");
//		}
//		return "redirect:/board/list" + cri.getListLink();
//	}
	@PreAuthorize("principal.username == #writer")
	@PostMapping("/remove")
	public String remove(@RequestParam("bno") Long bno, Criteria cri, RedirectAttributes rttr, String writer) {
		log.info("remove..." + bno);
		List<BoardAttachVO> attachList = service.getAttachList(bno);
		if (service.remove(bno)) {
			deleteFiles(attachList);
			rttr.addFlashAttribute("result", "success");
		}
		return "redirect:/board/list" + cri.getListLink();
	}

내용은 크게 다를게없다. 대신 표현식에서 차이가 있는데 이때 #wirter를 통해서 해당 작성자와 현재 username이 맞는지를 판단한다. 그리고 그 witer를 매개변수로 사용할 수 있다. 중요하다 이건

수정도 파라미터로 Board타입의 객체를 받로록 설계해서 변경해준다.

//	@PostMapping("/modify")
//	public String modify(BoardVO board, @ModelAttribute("cri") Criteria cri, RedirectAttributes rttr) {
//		if (service.modify(board)) {
//			rttr.addFlashAttribute("result", "success");
//		}
//		rttr.addAttribute("pageNum", cri.getPageNum());
//		rttr.addAttribute("amount", cri.getAmount());
//		return "redirect:/board/list";
//	}
	@PreAuthorize("principal.username == #board.writer")
	@PostMapping("/modify")
	public String modify(BoardVO board, Criteria cri, RedirectAttributes rttr) {
		log.info("modify:" + board);
		if (service.modify(board)) {
			rttr.addFlashAttribute("result", "success");
		}
		return "redirect:/board/list" + cri.getListLink();
	}

로그인이 되어있지않을때 수정기능이없다.

댓글기능또한이다.

하지만 본계정으로 들어가니 수정과 댓글기능이 활성화 되어있는걸 볼 수 있다.

그래서 댓글을 작성하려고보니 경고창에 이상한 것들이 나타난다. 

아마도 Ajax와 스프링시큐리티 단을 처리 하지않아서 일것같다.

다음 포스팅은 ajax와 스프링 시큐리티 처리에 대해 공부해 보곘다.

728x90
반응형
LIST

'Spring공부 > 4-스프링시큐리티' 카테고리의 다른 글

프로젝트(2)  (0) 2021.10.21
자동 로그인  (0) 2021.10.21
스프링 시큐리티와 JSP  (0) 2021.10.19
커스텀 UserDetailsService  (0) 2021.10.19
JDBC를 이용하는 간편 인증/ 권한처리  (0) 2021.10.18

댓글