[Spring] AOP를 이용한 로그인 인증 PointCut 예제

AOP

어플리케이션에서의 관심사의 분리(기능의 분리) 즉, 핵심적인 기능에서 부가적인 기능을 분리한다. 분리한 부가기능을 애스펙트(Aspect)라는 독특한 모듈형태로 만들어서 설계하고 개발하는 방법

 

AOP 사용이유

회원이라는 기능이 있고 회원만이 접근할 수 있는 url이 존재, 그 곳을 접근할 때는 회원의 session정보가 존재해야했음.

AOP pointcut 기능을 이용해서 모든 요청이 서블릿으로 들어올 때 before pointcut을 걸어두어 회원의 session정보가 존재하는지 검사.

 

package com.test.genius.code.pointcut;

import java.io.IOException;
import java.io.PrintWriter;

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

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.test.genius.code.util.MessageUtil;

@Component
@Aspect
public class LoginAuthPointcut {
	
	@Pointcut("execution(* com.test.genius.code.*.*.*Controller.*(..))")
	public void loginauth() {}
	
	@Before("loginauth()")
	public void commonAuth(JoinPoint joinPoint){
		Object[] obj = joinPoint.getArgs(); //request,response,session
		HttpSession session = (HttpSession)obj[2];
		
		try {
			if(session.getAttribute("id")!=null) {
				//로그인정보가 없으면 -> 쫓겨나야함. 로그인 페이지로.
				HttpServletRequest request = (HttpServletRequest)obj[0];
				HttpServletResponse response = (HttpServletResponse)obj[1];
				if(request.getRequestURL().toString().contains("/mainpage.genius")||
						request.getRequestURL().toString().contains("/logout.genius")	) {return;} //지금페이지가 mainpage면 괜찮다.
				PrintWriter writer;
				writer = response.getWriter();
				writer.print("<script>");
				writer.print("alert('"+MessageUtil.getMessage("login.essential", request)+"');");
				writer.print("location.href='/genius/mainpage.genius';");
				writer.print("</script>");
				writer.close();
			}//있으면 괜찮
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
}

@Component 어노테이션은 자바 클래스를 스프링 빈이라고 표시하는 역할을 한다. 이 어노테이션을 사용함으로써 스프링의 component-scanning 기술이 이 클래스를 어플리케이션 컨텍스트에 빈으로 등록하게 된다. 

 

@Aspect 어노테이션을 이용해서 공통 기능을 제공하는 Aspect 클래스를 작성할 수도 있다. @Aspect 어노테이션을 이용한 공통 기능 구현 방법은 POJO 방식과 크게 다르지 않다. 차이점이 있다면, @Aspect 어노테이션을 적용한 클래스에 공통 기능과 PointCut을 설정한다는 점이다.

 

@PointCut 어노테이션으로 부가기능을 담고 있는 객체(어드바이스 객체, 위의 LoginAuthPointCut클래스와 같은)를 적용할 타겟의 메서드를 선별하는 정규표현식을 담는다.

 

@Before 어노테이션을 loginauth()라는 메소드를 @PointCut 어노테이션으로 지정한 정규표현식에 부합하는 메소드들이 실행되기 전에 실행하겠다라는 의미이다. @After Throwing/Returning, @Around 의 종류가 있다.

 

JoinPoint 객체

JoinPoint객체는 쉽게말하면 각 컨트롤러에 정의된 메소드들의 args(매개변수)정보를 담고 있는 객체이다. 위의 코드에서는 getArgs메소드로 매개변수 배열을 생성한다. 여기서 생성된 배열의 index는 Controller 객체에 정의된 객체의 순서와 동일하다. 그렇기 때문에 Controller 메소드 정의할떄, request, response, session 객체 순으로 담았다.

 

이렇게 loginauth기능을 이용해서 현재 요청 url의 값을 받아 회원 session 정보를 갖지 않고 특정 url에 접근하는 경우 쫓아내도록 구현하였다.

댓글

Designed by JB FACTORY