[Spring][쇼핑몰 프로젝트] 12. 인터셉터 적용

YB·2023년 2월 15일
0

쇼핑몰

목록 보기
20/40

목표

 메인페이지에서 관리자 계정으로만 로그인하였을 때만 관리자 페이지로 이동할 수 있는 링크가 보이도록 하였습니다. 하지만 일반 계정 혹은 로그인하지 않더라도 관리자 페이지 url만 알고 있다면 접속을 할 수 있게 됩니다. AdminController.java에 있는 관리자 페이지 접속 메서드에 세션 체크를 통해 권한이 없는 관리자가 접근 시 메서드 실행이 되지 않도록 로직을 작성해야 합니다.

 문제는 해당 몇몇 개의 메서드막 적용해야 한다면 문제가 없지만 AdminController.java에서 작성된 메서드 들은 관리자가 사용할 메서드 들이기 때문에, 작성될 메서드 전체에 사용자 권한을 확인하는 코드를 작성해야 합니다.

 이러한 세션 체크 로직처럼 웹을 실행하기 위한 핵심 로직은 아니지만 반드시 필요한 로직들은 한번의 일괄적으로 관리해 줄 수 있도록 해주는 수단으로써 Interceptor가 있습니다. 이 Interceptor는 Controller를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 일종의 필터입니다.

인터셉터(Interceptor) 적용 대상은 2개입니다.
1. AdminController.java 전체
2. MemberController.java의 로그인 메서드

0. 관리자 페이지 및 수정

1) 관리자 페이지

관리자 페이지의 기본 틀을 만들었습니다.

main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="../resources/css/admin/main.css">
 
<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></script>
</head>
</head>
<body>
 
    <div class="wrapper">
        <div class="wrap">
            <!-- gnv_area -->    
            <div class="top_gnb_area">
                <ul class="list">    
                    <li><a href="/main">메인 페이지</a></li>
                    <li><a href="/member/logout.do">로그아웃</a></li>
                    <li>고객센터</li>            
                </ul>
            </div>
            <!-- top_subject_area -->
            <div class="admin_top_wrap">
                <span>관리자 페이지</span>
                
            </div>
            <!-- contents-area -->
            <div class="admin_wrap">
                <!-- 네비영역 -->
                <div class="admin_navi_wrap">
                    <ul>
                        <li >
                            <a class="admin_list_01">상품 등록</a>
                        </li>
                        <li>
                            <a class="admin_list_02">상품 목록</a>
                        </li>
                        <lI>
                            <a class="admin_list_03">작가 등록</a>                            
                        </lI>
                        <lI>
                            <a class="admin_list_04">작가 관리</a>                            
                        </lI>
                        <lI>
                            <a class="admin_list_05">회원 관리</a>                            
                        </lI>                                                                                             
                    </ul>
					<!-- 
                    <div class="admin_list_01">
                        <a>상품 관리</a>
                    </div>
                     -->
                </div>
                <div class="admin_content_wrap">
                    <div>관리자 페이지 입니다.</div>
                </div>
                <div class="clearfix"></div>
            </div>
        </div>
    </div>
 
</body>
</html>

main.css

@charset "UTF-8";
*{
    margin: 0;
    padding:0;
}
a{
    text-decoration: none;
}
ul{
    list-style: none;
}
/* 화면 전체 렙 */
.wrapper{
    width: 100%;
}
/* content 랩 */
.wrap{
    width : 1080px;
    margin: auto;
}
/* 홈페이지 기능 네비 */ 
.top_gnb_area{
    width: 100%;
    height: 50px;
    background-color: #f0f0f1;
    position:relative;
}
.top_gnb_area .list{
    position: absolute;
    top: 0px;
    right: 0;
    
}
.top_gnb_area .list li{
    list-style: none;    
    float : left;
    padding: 13px 15px 0 10px;
    font-weight: 900;
    cursor: pointer;
}
 
/* 관리제 페이지 상단 현페이지 정보 */
.admin_top_wrap{
    height:110px;
    line-height: 110px;
    background-color: #5080bd;
}
.admin_top_wrap>span{
    margin-left: 30px;
    display:inline-block;
    color: white;
    font-size: 50px;
    font-weight: bolder;
}
/* 관리자 wrap(네비+컨텐츠) */
.admin_wrap{
    
    
}
 
/* 관리자페이지 네비 영역 */
.admin_navi_wrap{
    width: 20%;
    height: 300px;
    float:left;
    height: 100%;
}
.admin_navi_wrap li{
    display: block;
    height: 80px;
    line-height: 80px;
    text-align: center;
}
.admin_navi_wrap li a{
    display: block;
    height: 100%;
    width: 95%;
    margin: 0 auto;
    cursor: pointer;
    font-size: 30px;
    font-weight: bolder;
}
/* 
.admin_list_01{
    background-color: #c8c8c8;
} */
 
 
/* 관리자페이지 컨텐츠 영역 */
.admin_content_wrap{
    width: 80%;
    float:left;
    height: 100%;
    height: 700px;
    
}
.admin_content_wrap div{
    margin-top: 280px;
    text-align: center;
    font-size: 50px;
    font-weight: bolder;
}
 
 
 
 
/* float 속성 해제 */
.clearfix{
    clear: both;
}

2) 로그인 url 수정

기존 로그인 url을 쓰는데 전혀 문제가 없지만, 이번에 사용할 인터셉터의 적용 대상을 정확히 타겟팅 하기 위해서 로그인 url을 약간 수정하였습니다. POST방식의 로그인 url을 기존 "login"에서 "login.do"로 변경하였습니다. 변경할 곳은 MemberController.java에 RequestMapping어노테이션 부분, login.jsp에 있는 <script>태그 내에 서버에 로그인을 요청하는 부분을 변경합니다.

1. Interceptro 기본설정

Interceptor를 사용하기 위해서 전체적으로 두 가지의 작업이 필요합니다.

첫 번째, spring-web 라이브러리 pom.xml에 추가합니다.
두 번째, 적용할 Interceptor 클래스(class)를 작성하고, 이를 적용하기 위해서 servlet-context.mxl에 적용시킬 경로와 적용할 클래스를 설정합니다.

1) spring-mvc 라이브러리 추가

spring-web 라이브러리를 추가해줍니다. 하지만 이미 spring-web라이브러리를 포함하고 있는 spring-webmvc를 추가해놓았기 때문에 따로 추가할 필요는 없습니다.

2) Interceptor 클래스 작성

Interceptor클래스를 따로 관리하기 위해서 com.test.interceptor패키지를 새로 만들었습니다. 그리고 AdminInterceptor.java와 LoginInterceptor.java클래스를 생성합니다.

3) servlet-context.xml 설정

우리가 적용할 대상은 "/admin"경로가 붙는 모든 url, 로그인을 수행하는 "login.do" url입니다. 따라서 serlvet-context.xml에 해당 url에 적용되도록 코드를 추가합니다. 또 우리가 생성한 Interceptor클래스가 Spring에서 인식하여 적용이 될 수 있도록 bean 코드도 추가해줍니다.

	<!-- 인터셉터 적용 -->
    <interceptors>
        <interceptor>
            <mapping path="/member/login.do"></mapping>
            <beans:bean id="loginIntreceptor" class="com.test.interceptor.LoginInterceptor"></beans:bean>
        </interceptor>
        <interceptor>
            <mapping path="/admin/**"></mapping>
            <beans:bean id="AdminIntreceptor" class="com.test.interceptor.AdminInterceptor"></beans:bean>
        </interceptor>
    </interceptors>

2. LoginInterceptor.java 구현

일어날 확률은 매우 낮지만 이전 작업 중 세션이 완전히 제거되지 않아 로그인을 위해 새로운 세션을 저장할 때 발생할 수 있는 에러를 방지하기 위해서 로그인 메서드가 있는 MemberController.java에 진입하기 전 세션을 제거하는 작업을 해줍니다.

  • 해당 클래스를 Interceptor로 사용하기 위해서 클래스 선언부에 HandlerInterceptor 상속을 선업합니다.
  • Controller에 진입하기 전에 작업을 원하기 때문에 preHandle()메서드를 오버라이딩합니다.
  • preHandel()메서드 구현부에 세션을 제거해주는 코드를 추가합니다.
public class LoginInterceptor implements HandlerInterceptor {
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		
		System.out.println("LoginInterceptor preHandle 작동");
		
		HttpSession session = request.getSession();
		
		session.invalidate();
		
		return true;
	}

}

3. AdminInterceptor.java 구현

관리자 메서드("/admin/**")에 접근하는 사 용자의 adminCk가 1인지 확인하는 작업이 핵심입니다. "member" session 정보를 MemberVO타입의 변수에 담은 후, 해당 변수를 통해 adminCk의 값을 호출하여 비교하는 로직을 작성해주어야 합니다.

  • LoginInterceptor.java와 동일하게 HandlerInterceptor클래스를 상속시키고 preHandle()메서드를 오버라이딩합니다.
  • 먼저 "member" session을 호출하여 MemberVO타입의 lvo변수에 저장합니다. (MemberVO타입으로 형변환해주어야합니다.)
  • if문을 통해서 lvo가 null이거나 getAdminCk()메서드 반환 값이 0이면 main페이지로 리다이렉트 되도록 코드를 추가 후 false를 반환하도록 로직을 작성합니다. 아닐 경우 AdminController.java에 접근할 수 있도록 true를 반환하도록 작성합니다.
public class AdminInterceptor implements HandlerInterceptor {
	
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		
		HttpSession session = request.getSession();
		
		MemberVO lvo = (MemberVO)session.getAttribute("member");
		
		if(lvo == null || lvo.getAdminCk() == 0) {	// 관리자 계정이 아닌 경우
			
			response.sendRedirect("/main");	// 메인페이지로 리다이렉트
			
			return false;
			
		}
		
		return true; 	// 관리자 계정 로그인 경우(lvo != null && lvo.getAdminCk() == 1)
	}

}

4. 테스트

- 로그인을 진행하여 console창에 문구 확인

- 로그인하지 않은 상태에서 url("/admin/main") 접근

  • 일반계정 로그인 상태에서 url("/admin/main") 접근

profile
개인이 공부한걸 작성하는 블로그입니다..

0개의 댓글