Acegi 사용시 사용자 정보 접근하기

Acegi를 사용하여 인증을 거치면, 사용자 아이디(principal)가 session에 ACEGI_SECURITY_LAST_USERNAME 라는 속성으로 저장됩니다.

따라서, 뷰에서는 EL을 사용하여 ${ACEGI_SECURITY_LAST_USERNAME} 이런식으로 접근할 수 있으며, 컨트롤러 계층에서는

String loginId = (String) request.getSession().getAttribute(“ACEGI_SECURITY_LAST_USERNAME”);

이런식으로 접근할 수 있습니다.

HttpServletRequest 변수에 직접 전근할 수 없는 계층에서도 현재 로그인 되어 있는 사용자 정보에 접근할 수 있습니다.

String username = SecurityContextHolder.getContext().getAuthentication().getName();

이런 식으로 SecurityContextHolder를 통해서 현재 로그인 되어 있는 사용자의 정보를 가져올 수 있습니다.

Acegi Security in one hour

시기적절하게 좋은 글 하나가 올라왔네요.
Acegi Security in one hour

Spring 2, Acegi, Sitemesh를 사용한 예제를 코드 중심으로 설명한 아티클입니다. 자세하기 보진 않았지만, 빠르게 Acegi를 사용해 보고 싶으신 분들에게 매우 유용할 듯 싶습니다. 제목은 한 시간이지만, 영어권이 아니기 때문에 한 두 시간정도가 되지 않을까 싶네요.ㅎㅎ

왜 이름이 Acegi 인가?

Acegi Security의 이름이 왜 Acegi인가에 대해 Acegi를 만든 Ben Alex가 2007년 1월에 작성했던 글이 있습니다.

정말 영어 알파벳 홀수 1, 3, 5, 7, 9를 따서 만든거라고 합니다. 다만 처음 부터 지금의 Acegi Sicurity용으로 만든 이름을 아니였고 다른 시스템을 일컷는 것 같은데 BBS라고 하는데 뭔지 모르겠군요.

Anyway, 2003년 11월에 만들어서 ZIP 파일로 들고가서 로드 존슨과 융겐 휄러에게 보여주며 Spring Security로 제안을 했지만… 둘 다 너무 바쁜 나머지 제대로 검토할 시간이 없어서 Spring Security라고 하지 못하고 XXX Security System for Spring으로 이름을 지어야 했는데.. 그 때 바로 위에서 사용했었던 Acegi를 사용한 것이라고 합니다.

지금은 당당히 Spring Security라는 새 이름을 가지게 되었고, 단순한 이름의 변경이외에도 다양한 의미가 내포된 것 같군요.

Acegi의 엄청난 설정 내용을 보면서 전부 새로운 태그를 만들어서 확 줄이고 싶다는 생각이 들었는데.. 아마도 만들고 있겠죠?? Spring 2.1에 추가된 <context:annotation-config/> 이런 태그 처럼 여러개의 bean을 등록해야 할 때 묶어서 한방에 등록해주고 자주 설정하는 부분은 속성으로 설정할 수 있도록 해주면 훨씬 간편해 질 거라는 생각만 해봤습니다. 태그 만드는 방법은 토비님의 예전 포스팅에도 있었고 KSUG 1회 때의 약간 어려웠던 발표도 있었으며, Ben Hale의 Creating a Spring 2.0 namespace? Use Spring’s AbstractBeanDefintionParser hierarchy. 이런 글도 있지만.. 아직 해보진 못했습니다. 해봐야겠네요. 앗. 갑자기 삼천포;;

Spring Acegi 예제 애플리케이션

어제 올렸던 Spring Acegi Tutorial 아티클에서 사용한 예제 애플리케이션입니다. Acegi의 핵심 기능인 인증과 권한을 테스트 해보기 위한 매우 간단한 예제 애플리케이션입니다.

dn323.zip

Spring 1.2 rc1, Acegi 1.0.0 rc2 를 사용한 코드입니다.
JDK 5.0 이상, Tomcat 5.5 이상에서 동작합니다.

사용법은 간단합니다. 톰캣으로 돌리면 다음과 같은 화면을 볼 수 있습니다.
사용자 삽입 이미지여기서 위쪽 링크는 일반 user만 들어갈 수 있고 아랫 쪽 링크는 admin만 들어갈 수 있습니다. dispatcher-servlet.xml의 userDetailsService 빈을 살펴 보시면 해당 메모리 DB로 id, 비번, role 을 설정 해 둔 것을 볼 수 있습니다.
사용자 삽입 이미지위 쪽 링크를 클릭하시면 인증 화면이 뜹니다. 여기서 user, userpass 라고 입력하시면 일반 user로 로그인 할 수 있습니다.
사용자 삽입 이미지로그인에 성공하면 다음과 같은 일반 폼 화면이 뜨고 여기서 아무 값이나 입력하면 결과를 확인할 수 있습니다. 그리고 로그아웃도 할 수 있죠. 만약 위의 로그인 화면에서 로그인이 실패하면 다음과 같은 페이지를 볼 수 있습니다.
사용자 삽입 이미지이번에는 admin만 접근할 수 있는 첫 번쨰 화면의 두 번째 링크로 들어가겠습니다. admin의 id와 비번은 admin, adminpass입니다.
사용자 삽입 이미지자 이제 거의 다 테스트를 해봤습니다. 한 가지만 해보면 끝입니다. admin 로그인 화면 또는 user 로그인 화면에서 해당 권한이 없는 id와 비번으로 로그인을 시도합니다. 즉 admin 로그인 창에서 user/userpass를 입력합니다. 그럼 다음과 같은 화면을 볼 수 있습니다.
사용자 삽입 이미지누가 이런 일을 했을까요? ExceptionTranslationFilter 이겠죠? 물론 보여준건 브라우져지만, 브라우져에게 403 에러를 보낸 건 ExceptionTranslationFilter의 일 중 하나입니다.
dn323.zip

Spring Acegi Tutorial

참조 :  Spring Acegi Tutorial

Spring Security(Acegi Security)에 대한 맛보기용 아티클로 매우 적당한 것 같습니다. 먼저 Acegi에서 흔히 사용하는 용어에 대해 설명을 하고, 간단한 애플리케이션을 통해 실제 Acegi를 적용하여 구동하고 있는 녀석을 살펴본 뒤에, 해당 샘플에서 사용한 필터들과 각각의 필터들의 종속성을 살펴보고 있습니다. 개인적으로는 이러한 구성이 어렵고 생소한 프레임워크를 공부하는데 가장 좋은 것 같습니다.

Acegi에서 사용하는 용어
– Authentication(인증) : “너는 누구냐?”
    – principal(주체) : username
    – credentials(신용) : password
– Authorization(권한) : “뭐 할려고?”
    – object definitions : secured resources, 관계자외 출입 금지인 자원

샘플 애플리케이션  사용자 삽입 이미지– 두 링크 모두 로그인으로 인증을 하며, 이때 validation을 해서 에러페이지로 이동시킬 수 있습니다.
– 특정 url과 role을 맵핑한 정보를 사용하여 권한 체크를 합니다.

샘플에서 사용한 필터들과 그들의 종속성
사용자 삽입 이미지사용자 삽입 이미지사용자 삽입 이미지예전에 토비님께서 작성하셨던 “나의 Spring Acegi Security Framework 학습기“에 보면 더 많은 필터들이 있지만 일단 여기서는 위의 예제에서 사용한 httpSessionContextIntegrationFilter, authenticationProcessingFilter, exceptionTranslationFilter, filterInvocationInterceptor 네 개만 살펴보겠습니다.

1. AuthenticationProcessingFilter(위 그림에서 formAuthenticationProcessingFilter)
Http Request가 지나가는 첫 번째 필터로 인증과 관련된 요청을 처리하는데 특화된 필터 입니다. 즉, 로그인과 관련된 요청에 특화 되었기 때문에 폼 서브밋 URL 값(filterProcessUrl 속성)이나 로그인 실패시 URL 값(authenticationFailureUrl 속성)들을 설정합니다.

2. HttpSessionContextIntegrationFilter
위에서 살펴보았던 AuthenticationProcessingFilter가 사용하고 있는 AuthenticationManager에 의해 만들어지고 관리되는 Authentication 객체를 Thread Local을 사용하여(servlet이 thread기반이라..) 감싸서(wrap) 해당 쓰레드 내의 여러 request에서 같은 Authentication 객체를 공유할 수 있도록 하는 역할을 합니다.

3. ExceptionTranslationFilter
security 시스템의 중추적인 역할을 하는 두 개의 필터 중에 하나이며(다른 하나는 FilterSecurityInterceptor), 인증과 권한에 관련되어 발생하는 예외(AcegiSecurityException)를 잡아서 다음의 두 가지 중 하나로 처리 합니다.
– Authentication 객체 부재로 인한 예외 일 경우 : AuthenticationEntryPoint 를 사용하여 사용자에게 로그인을 요구함.
– FilterSecurityInterceptor에 의해 던져진 권한이 없어서 발생한 예외 일 경우 : 브라우저에게 SC_FORBIDDEN (HTTP 403) 에러를 던집니다.

4. FilterSecurityInterceptor
secured resources에 대한 정의를 담고 있습니다. 이곳에서 실제 특정 URL과 role을 맵핑하는 정보인 objectDefinitionSource 속성을 설정하고 있습니다. 이 속성을 설정할 때는 두 개의 dialect를 지정해 줍니다. 이름만 봐도 대강 짐작이 가는 dialect기 때문에 설정 내용을 살펴보시면 됩니다.
사용자 삽입 이미지