반응형

 

자동 로그인

 

: 로그인하면 특정 시간 동안 다시 로그인 할 필요가 없는 기능 (쿠키를 사용)

 

 

테이블 생성

--DDL : auto commit;
CREATE TABLE PERSISTENT_LOGINS(
    USERNAME VARCHAR2(200), 
    SERIES VARCHAR2(200),
    TOKEN VARCHAR2(200),
    LAST_USED DATE,
    CONSTRAINT PK_PL PRIMARY KEY(SERIES)
);

 

 

security-context.xml

</security:http> 안의 로그아웃 정보 변경

data-source-ref - db 연결하는 정보와 연결함

 

security:logout 에서 delete-cookies를 설정
security:remember-me에서 DB 정보 기입 후 쿠키 유효시간 설정 => 자동으로 PERSISTENT_LOGINS 테이블에 들어감(테이블의 이름과 컬럼 갯수 등 수정하면 안 됨. 자체적으로 제공해주는 기능이기에 그대로 사용해야함)

<!-- dataSource를 통해 지정한 Database의 
약속된 테이블(persistent_logins) 를 이용하여 기존 로그인 정보를 기록함 

token-validity-seconds : 쿠키의 유효시간(초) 7일로 설정
-->
<security:remember-me data-source-ref="dataSource"
    token-validity-seconds="604800"
/>

<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화(session.invalidate())함 
/logout : post방식 요청URI -> form의 action="/logout"에서 사용 

로그아웃을 하면 자동 로그인에 사용된 쿠키도 함께 삭제해 줌.
-->
<security:logout logout-url="/logout" invalidate-session="true" 
    delete-cookies="remember-me,JSESSION_ID" />

 

 

loginForm.jsp

자동 로그인 부분 수정

name을 remember-me로 기입 (이름은 고정!)

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

<div class="login-box" style="margin:auto;">
	<div class="card">
		<div class="card-body login-card-body">
			<p class="login-box-msg">Sign in to start your session</p>
			<form action="/login" method="post">
				<div class="input-group mb-3">
					<!-- 아이디 
					name="username" 으로 꼭 써야함 -->
					<input type="text" name="username" id="username" class="form-control" placeholder="아이디">
					<div class="input-group-append">
						<div class="input-group-text">
							<span class="fas fa-envelope"></span>
						</div>
					</div>
				</div>
				<div class="input-group mb-3">
				<!-- 비밀번호
				name="password" 으로 꼭 써야함 -->
					<input type="password" name="password" id="password" class="form-control" placeholder="비밀번호">
					<div class="input-group-append">
						<div class="input-group-text">
							<span class="fas fa-lock"></span>
						</div>
					</div>
				</div>
				<div class="row">
					<div class="col-8">
						<div class="icheck-primary">
							<!-- 로그인 상태 유지 체크박스 
								체크 시 : PERSISTENT_LOGINS 테이블에 로그인 로그 정보가 insert 됨
								name을 remember-me로 해야함
							-->
							<input type="checkbox" name="remember-me" id="remember">
							<label for="remember"> 자동 로그인 </label>
						</div>
					</div>
					<div class="col-4">
						<button type="submit" class="btn btn-primary btn-block">Sign In</button>
					</div>
				</div>
				
				<!-- csrf : Cross Site Request Forgery 
				sec: 를 사용하기 위해선 상단에 추가해야함
				taglib prefix="sec" uri="http://www.springframework.org/security/tags -->
				<sec:csrfInput/>
			</form>
		</div>
	</div>
</div>

 

결과 화면1 : 로그인 시 추가, 로그아웃 시 삭제됨

 

 

 

  • 쿠키 정보 확인

register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
//request객체 안에 있는 쿠키들을 확인
Cookie[] cookies = request.getCookies();

out.print("<p>쿠키의 개수 : " + cookies.length + "</p>");
%>

<h2>로그인 한 관리자만 접근 가능</h2>
<h3>/notice/register.jsp</h3>

 

결과 화면2-1 : localhost/notice/register 로 url 들어감

 

결과 화면2-2 : 쿠키 추가된 것을 확인할 수 있음

 

 

 

스프링 시큐리티 애너테이션

 

: 메서드가 실행되기 전에 적용할 접근 정책을 지정 시 사용

 

 

주로 사용하는 애너테이션 : @PreAuthorize

 

변경되는 부분 확인

 

 

 

  • 회원만 접근

security-context.xml
security:intercept-url 전부 주석 처리함

 


servlet-context.xml
beans:beans 에 추가 => security:global-method-securit를 사용하기 위해서 추가한 것

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:beans="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:security="http://www.springframework.org/schema/security" 
   xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
      http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/security 
      http://www.springframework.org/schema/security/spring-security-4.2.xsd">

 

</beans:beans> 안에 추가

<!-- 스프링 시큐리티 애너테이션을 활성화
- pre-post-annotations="enabled" -> 골뱅이PreAuthorize, 골뱅이PostAuthorize 활성화
  *** PreAuthorize : 특정 메소드를 실행하기 전에 role 체킹
  PostAuthorize : 특정 메소드를 실행한 후에 role 체킹
- secured-annotations="enabled" -> 골뱅이Secured를 활성화
  Secured : 스프링 시큐리티 모듈을 지원하기 위한 애너테이션
-->
<security:global-method-security pre-post-annotations="enabled"
    secured-annotations="enabled"/>

 

 

CustomAccessDeniedHandler.java
sendRedirect 부분 변경

package kr.or.ddit.security;

import java.io.IOException;

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

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler{

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException, ServletException {
		log.info("handle");
		
		//redirect : 새로운 URI를 요청
//		response.sendRedirect("/accessError");
		response.sendRedirect("/login");
	}
}

 

 

BoardController.java

package kr.or.ddit.controller;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import kr.or.ddit.dao.BoardDao;
import kr.or.ddit.vo.BoardVO;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@Controller
@RequestMapping("/board")
public class BoardController {

	@PreAuthorize("hasRole('ROLE_MEMBER')")
	@RequestMapping(value="/register", method=RequestMethod.GET)
	public String registerForm() {
		log.info("registerForm에 왔다");
		
		//ModelAndView가 없음
		//mav.setViewname("board/register") 생략
		
		//forwarding : jsp
		return "board/register";
	}
	
	/*
		요청URI : /board/register
		요청파라미터 : 
		요청방식 : post
	 */
	@RequestMapping(value="/register", method=RequestMethod.POST)
	public String registerPost() {
		log.info("registerPost에 왔다");
		
		//forwarding : /views/success.jsp
		return "success";
	}
}

 

 

CommonExceptionHandler.java
@ControllerAdvice를 삭제

 

 

결과 화면3 : http://localhost/board/register로 입력 시 로그인 화면이 뜸

 

 

 

  • 관리자만 접근

NoticeController.java

@PreAuthorize 추가

package kr.or.ddit.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;

@RequestMapping("/notice")
@Slf4j
@Controller
public class NoticeController {

	//요청 URI : /notice/list
	@GetMapping("/list")
	public String list() {
		//forwarding : jsp
		return "notice/list";
	}
	
	//요청 URI : /notice/register
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@GetMapping("/register")
	public String register() {
		//forwarding : jsp
		return "notice/register";
	}
}

 

 

register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
//request객체 안에 있는 쿠키들을 확인
Cookie[] cookies = request.getCookies();

out.print("<p>쿠키의 개수 : " + cookies.length + "</p>");

for(int i =0;i<cookies.length;i++){
   out.print(cookies[i].getName()+":"+cookies[i].getValue()+"<br/>");
}
%>

<h2>로그인 한 관리자만 접근 가능</h2>
<h3>/notice/register.jsp</h3>

 

결과 화면4-1

 

결과 화면4-2

 

 

 

  • 예시

BookController.java

 

하단의 셋 중에 하나 사용 가능

@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_MEMBER')")
@PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_MEMBER')")
@Secured({"ROLE_ADMIN","ROLE_MEMBER"})

 

package kr.or.ddit.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;


import kr.or.ddit.service.BookService;
import kr.or.ddit.utils.ArticlePage;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class BookController {
	
	// 요청URI : /create
	// 요청 파라미터 : 
	// 요청방식 : get
	// 로그인(인증) 한 관리자 또는 회원(인가)만 접근 가능
//	@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_MEMBER')")
//	@PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_MEMBER')")
	@Secured("{'ROLE_ADMIN','ROLE_MEMBER'}")
	@RequestMapping(value = "/create", method=RequestMethod.GET)
	public ModelAndView create() {
		ModelAndView mav = new ModelAndView();
		
		// name : title / value = "도서생성"
		mav.addObject("title", "도서생성");
		// jsp
		mav.setViewName("book/create");
		
		return mav;
	}
	
}

 

결과 화면5-1 : http://localhost/create 로 들어가서 로그인

 

결과 화면5-2

 

 

 

  • 로그인 해야 메소드 접근 가능

EmployeeController.java

class 밖에 추가

// 이 클래스의 모든 메소드에 접근하려면 로그인 된 상태여야 함
@PreAuthorize("isAuthenticated()")

 

결과 화면6-1 : http://localhost/employee/create로 들어올 시 화면

 

결과 화면6-2 : 로그인 한 후 화면

 

 

 

 

 

1. 공지사항 등록 - 로그인 한 관리자만 접근 가능
골뱅이PreAuthorize("hasRole('ROLE_ADMIN')")
골뱅이PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_MEMBER')")

2. 공지사항 등록 - 로그인(인증) 한 관리자 또는 회원(인가)만 접근 가능
골뱅이PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_MEMBER')")   
골뱅이Secured({"ROLE_MEMBER","ROLE_ADMIN"})

3. 공지사항 등록 - 로그인(인증) 한 관리자 이면서 회원(인가)만 접근 가능
골뱅이PreAuthorize("hasRole('ROLE_ADMIN') and hasRole('ROLE_MEMBER')")

4. 로그인한 사용자만 접근 가능(권한과 상관 없음)
골뱅이PreAuthorize("isAuthenticated()")

5. 로그인 안 한 사용자가 접근 가능 -> 로그인 한 사용자는 접근 불가
골뱅이PreAuthorize("isAnonymous()")

6. 누구나 접근 가능(PreAuthorize 생략)

 

 

 

반응형