자동 로그인
: 로그인하면 특정 시간 동안 다시 로그인 할 필요가 없는 기능 (쿠키를 사용)
테이블 생성
--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> 안의 로그아웃 정보 변경
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>
- 쿠키 정보 확인
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>
스프링 시큐리티 애너테이션
: 메서드가 실행되기 전에 적용할 접근 정책을 지정 시 사용
주로 사용하는 애너테이션 : @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를 삭제
- 관리자만 접근
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>
- 예시
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;
}
}
- 로그인 해야 메소드 접근 가능
EmployeeController.java
class 밖에 추가
// 이 클래스의 모든 메소드에 접근하려면 로그인 된 상태여야 함
@PreAuthorize("isAuthenticated()")
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 생략)
'스프링 프레임워크' 카테고리의 다른 글
[스프링 프레임워크] 31장 sweetalert, 모달, 사진 파일 D드라이브에 저장 (0) | 2024.05.21 |
---|---|
[스프링 프레임워크] 30장 다음 우편번호, 주소 가져오기, 계층형 구조 (0) | 2024.05.20 |
[스프링 프레임워크] 28장 스프링 시큐리티2 (0) | 2024.05.17 |
[스프링 프레임워크] 27장 스프링 시큐리티1 (0) | 2024.05.16 |
[스프링 프레임워크] 26장 트랙잭션, 예외처리 (0) | 2024.05.16 |