[TIL] Day34 - 세션 유효범위 / 인터셉터

JIONY·2022년 9월 26일
0

TIL - Web BE - Spring Boot

목록 보기
10/20
post-thumbnail

jsp에 조건 걸어서 ~일 때만 이 메뉴가 나오게 해랏.. 이것만 하다가 인터셉터로 아예 막아버릴 수도 있게 됐음 성벽 쌓는 느낌ㅋㅋㅋ


세션 유효범위

어떤 웹페이지에 로그인한 상태로 같은 브라우저에서 새 탭/새 창으로 재진입하면 로그인이 되어 있음(세션이 같음). 브라우저가 다르면 로그인을 새로 해야 함(세션이 다름)

세션 ID와 신규 세션인지 검사하는 명령을 통해 직접 확인할 수 있음

  • 세션 ID(식별자): 세션에 부여되는 고유번호(16진수 32자리)
  • 신규 세션은 세션이 생성될 경우(신규 접속)만 true 반환
  • +) pageContext는 페이지 내에서 사용 가능한 도구를 제공함
<!-- 사용자 세션과 관련된 정보 출력 -->
세션 ID: ${pageContext.session.getId}<br>
신규 세션 여부: ${pageContext.session.isNew()}<br>

<!-- 로그인 시, 세션에 저장하는 정보 -->
loginId: ${sessionScope.loginId}<br>
로그인 여부: ${sessionScope.loginId != null}<br>
loginGrade: ${sessionScope.loginGrade}<br>
관리자 여부: ${sessionScope.loginGrade == '관리자'}<br>


메뉴별 접근 권한 설정

로그인 여부, 회원의 등급 등에 따라 메뉴별 접근 권한을 설정할 수 있음. 로그인 이후 해당 회원의 등급을 알아내는 방법은 아래 두 가지가 있음. DB를 최소한으로 접근하는 것이 성능에 도움이 되므로

  1. 검사가 필요한 시점에 아이디를 이용해 회원 정보를 조회
    - 장점: 중간에 회원 등급이 변경된 경우에도 제대로 작동함
    - 단점: DB를 매번 사용
    - 일반적으로 자주 바뀌는 정보에 대해서는 이 방식을 사용함

  2. 로그인 시 세션에 권한도 같이 저장 ✅
    • 장점: DB에 한 번만 접근
    • 단점: 중간에 회원 등급이 변경된 경우 재로그인시까지 반영되지 않음

두 가지 방법 모두 가능하기 때문에 효율과 성능 측면도 고려대상이 됨. 회원 등급은 쉽게 변경되지 않고, 매 페이지마다 검사가 필요함. DB를 최소한으로 접근하는 것이 성능에 도움이 되므로 이 상황에서는 2번이 적합하다고 볼 수 있음


권한(등급) 검사

  1. 세션에 저장된 등급 값을 꺼내오기

    • ${sessionScope.loginGrade}
    • 축약: ${loginGrade}
  2. 값 비교

    • ex. ${loginGrade == '관리자'}
    • 변수를 지정해 변수 이름으로 필요한 곳에 쉽게 불러오는 것도 가능함
    <!-- 관리자 등급 검사 -->
    <c:set var="admin" value="${loginGrade == '관리자'}"></c:set>

인터셉터

  • 서버의 처리 과정에 개입해서 원하는 방향의 작업을 추가하는 도구(간섭 객체)
  • 특정 클래스(deprecated)나 인터페이스(HandlerInterceptor)를 상속받아 자격을 획득해야 함
  • 간섭 시점(3개)에 따라 원하는 메소드를 재정의하여 사용
    • 작업 시작 전(preHandle)
      • ex. 비회원이 회원기능에 접근하는 것을 차단할 때
    • 작업 중(postHandle)
    • 작업 종료 후(afterCompletion)

Dispatcher Servlet

HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러.

컨트롤러를 구현해두기만 하면 디스패처 서블릿이 알아서 적합한 컨트롤러에 요청을 넘겨 처리하도록 하고, 결과를 응답받아 처리가 가능한 뷰에서 완성된 뷰를 받고, 클라이언트에 응답을 보냄


@Component

Component는 단일 기능을 수행하는 도구에 사용하는 어노테이션. 설정 클래스를 추가해서 interceptor로써도 작동할 수 있도록 해야 함(인터셉터 클래스 주입, preHandle 등 추가 처리)

  • +) Controller, Repository 등 빈을 등록만 하면 본래 용도로만 쓸 수 있는 도구로 작동

인터셉터 예시

@Component //단일 기능을 수행하는 도구
public class MemberInterceptor implements HandlerInterceptor {
	@Override
    public boolean preHandle(
              HttpServletRequest request, //요청 정보가 담긴 객체
              HttpServletResponse response, //응답 정보가 담긴 객체
              Object handler //이 요청을 실행할 매핑(메소드) 정보
              ) throws Exception {
              
    	//시나리오
		//1. 접속한 사용자가 로그인 상태인지 검사(request 객체 필요)
		//- HttpSession에 loginId라는 값이 있는지 검사
		//2. 상태에 따라 통과/차단 설정
		//- 1) 로그인 : 통과(return true)
		//- 2) 로그인x : 로그인 페이지로 리다이렉트 후 차단
		
		//1. 세션이 없을 때는 HttpServletRequest에서 획득 가능
		HttpSession session = request.getSession();
		String loginId = (String) session.getAttribute("loginId");
		if(loginId == null) { //비회원(2-2)
        	//절대경로 사용
        	response.sendRedirect("/member/login");
			return false; //차단
		}else {//회원(2-1)
			return true; //통과
		}
    }	
}

InterceptorConfiguration

인터셉터를 사용하기 위해 필요한 설정 클래스이므로 addInterceptors()를 오버라이딩 해야 함. 이미 등록해둔 인터셉터 클래스 파일도 주입이 필요함

  • application.properties에서 설정하기 어려운 복잡한 설정을 구현
  • @Configuration 어노테이션을 통해 빈 등록
  • 프로그램 동작 방식과 관련된 설정일 경우 특정 인터페이스 상속 필요
    • interface WebMvcConfigurer
  • 잘 만들어진 기능에 통과/차단 로직을 추가하는 것이므로 인터셉터를 처음부터 미리 만들 필요 없음

 package com.jw.springhome.configuration;
    
//의존성 import 생략
    
import com.jw.springhome.interceptor.MemberInterceptor;
    
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
	@Autowired
	private MemberInterceptor memberInterceptor;
    	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
    	//registry에 추가해 인터셉터가 작동하도록 설정
    	registry.addInterceptor(memberInterceptor)
        			//차단할 특정 주소 작성
    				.addPathPatterns("/**"); 
    }
}

간섭할 주소 설정방법

  • addPathPatterns()
  • 와일드카드(*) 사용 가능
  • 와일드카드(*)의 개수에 따라 의미가 달라짐
    • 1개: 현재 endpoint 내에서 어떤 글자가 와도 상관없다는 의미
    • 2개: 현재 endpoint와 하위 전체에서 어떤 글자가 와도 상관없다는 의미
  • 전체 주소를 추가하고 일부를 뺄 수 있음
    • excludePathPatterns()에 제외할 주소 추가

0개의 댓글