하나의 애플리케이션에 두 개의 인증!

스프링 시큐리티를 프로젝트에 적용하면서 가장 좋은 케이스는 기본적인 설정을 조정하는 것만으로도 고객의 요구사항을 만족시킬 수 있을 때입니다. 특히나 스프링 시큐리티는 커스터마이징을 하게 되면 예상치 못한 상황에서 그것을 컨트롤하기 어려우므로 더더욱 그러합니다. 하지만, 불행히도 이번 프로젝트를 진행하는 동안 그러한 상황에 부딪혔습니다.

상황

현재 진행하는 프로젝트에서 쇼핑몰에 스프링 시큐리티를 적용했습니다. 처음에는 고객에 대한 로그인과 그에 따른 권한처리를 하고 있었습니다. 가장 일반적인 스프링 시큐리티 적용 사례라고 하고 할 수 있었습니다. 기본 설정에 더해서 로그인시 필요한 사용자 정보를 가져오는 부분과 인증 객체만 커스터마이징해서 사용하고 있었습니다.

여기에 추가로 들어온 요구사항은 고객이 로그인함과 동시에 관리자의 로그인이 가능해야 한다는 것입니다. 간단하게 ROLE_ADMIN만 주어지면 되는 문제가 아니었습니다. 관리자 권한이 들어 오면서 로그인을 시작하는 entry point 및 성공/실패시 포워딩 되는 url까지 달라지게 되어서 한 애플리케이션이지만 마치 두 개의 애플리케이션과 같은 설정을 적용해야 하는 상황이 왔습니다.

해결방법

애플리케이션 하나에 두개의 인증 처리 방식을 해야 한다면 설정도 url 패턴을 토대로 둘로 나눠서 하기로 했습니다. 아래와 같이 /admin을 포함하는  url 패턴과 아닌 것을 정규표현식으로 나누어 보았습니다. 이런식으로 한 개의 애플리케이션안에서 아래와 같이 설정을 해주게 되면 인증 영역을 2개로 나눌 수 있게 됩니다. 더불어 관리자 세션의 key도 다르게 설정하여 세션도 2개가 되고 일반 사용자와 관리자가 동시에 로그인 할 수 있게 됩니다.

admin 포함 경로에 대한 설정

<http use-expressions=”true” entry-point-ref=”authAdminEntryPoint” authentication-manager-ref=”adminAuthenticationManager”

pattern=”^(/admin).*$” path-type=”regex” security-context-repository-ref=”adminSecurityContextRepository” >

<access-denied-handler ref=”accessDeniedHandler” />

<intercept-url pattern=”^(/admin/).*$” access=”hasRole(‘ROLE_ADMIN’)” />

<custom-filter ref=”customAdminAuthenticationFilter” position=”FORM_LOGIN_FILTER” />

<logout logout-url=”/logout” logout-success-url=”/adminLogin” invalidate-session=”true” delete-cookies=”SPRING_SECURITY_REMEMBER_ME_COOKIE” />

</http>
  1. 엘리먼트의어트리뷰트설명
  • use-expressions : SpEL을 사용하도록 한다는 설정입니다.
  • entry-point-ref : 내부적으로 지원하는 인증 방식이 아닌 다른 방법을 사용하고 있어서 새로운 인증 필터와  EntryPoint를 사용한다면 새로 만든 EntryPoint를 이곳에 설정합니다.
  • pattern : /admin 이 포함되는 url에 대한 인증은 여기서 처리하겠다는 설정입니다. 참고로 여기서는 정규표현식으로 표현된 방법이고, 정규표현식으로 사용하지 않으려면 pattern="/admin/**" 이런식으로 적어도 됩니다.
  • path-type : 앞에서 적었던 pattern이 어떤 형식으로 되어 있는지 적어줍니다. regex 외에도 ant가있습니다.
  • security-context-repository-ref : 요청 동안에 security context가 어떻게 저장될 것인지를 설정합니다. 이 부분을 따로 설정해주어 세션 두 개를 유지할 수 있을 수 있게 됩니다.

<access-denied-handler> 엘리먼트 : 인증이 정상적으로 처리되지 않고 중간에 예외 발생시에 처리해주는 핸들러를 설정해 줍니다.

<intercept-url> 엘리먼트 : 특정 url 패턴은 어떤 권한이 있어야 허용하겠다는 설정을 하는 부분입니다.

  • pattern : 특정 url 패턴을 적어줍니다.
  • access : 앞에 적어준 pattern에 대하여 어떤 권한을 허용할 것인지를 설정합니다. 위의 예제에서는 관리자에게만 허용하기 위하여 관리자 권한인 'ROLE_ADMIN'에 대해서만 허용했습니다. 이 부분은 조금 더 다양하게 표현 가능합니다.
  1. <custom-filter> 엘리먼트 : 내부에서 기본적으로 제공하는 필터 외에 사용자가 만든 필터를 적용할 수 있습니다.
  • ref : 임의로 만든 필터의 이름을 적어줍니다.
  • position : 기본으로 되어 있는 필터를 위치할 자리를 적어줍니다. position으로 적어 주면 기존에 있던 필터를 대체하여 동작하게 됩니다.  position 대신에 after와 before를 적어줄 수가 있는데 position과 달리 기존의 필터를 대체하지 않고 적어준 필터를 기본으로 앞이나 뒤에 위치하게 됩니다.
  1. <logout> 엘리먼트 : 로그아웃 필터의 기본 설정을 바꿀 수 있습니다.
  • logout-url : 기본으로 되어 있는 가상의 url을 임의로 바꿔줄 수 있습니다.
  • logout-success-url : 로그아웃이 성공했을 때, 이동할 url을 적어줍니다.
  • invalidate-session : 로그아웃을 했을 때, 세션이 무효화될 것인지를 설정합니다.
  • delete-cookies : 세션이 무효화될 때 삭제될 쿠키이름을 적어줍니다.

admin 미포함 경로에 대한 설정

<http use-expressions=”true” entry-point-ref=”authEntryPoint” authentication-manager-ref=”authenticationManager”pattern=”^(?!/admin).*$” path-type=”regex” >

<intercept-url pattern=”^(/order/cartList).*$” access=”hasRole(‘ROLE_CUSTOMER’)” />

<access-denied-handler ref=”accessDeniedHandler” />

<custom-filter ref=”customAuthenticationFilter” position=”FORM_LOGIN_FILTER” />

<logout logout-url=”/j_spring_security_logout” logout-success-url=”/” invalidate-session=”true” delete-cookies=”SPRING_SECURITY_REMEMBER_ME_COOKIE” />

<custom-filter ref=”customRememberMeFilter” position=”REMEMBER_ME_FILTER”/>

</http>

반복되는 내용이므로 위의 설명으로 대체하겠습니다.

관리자 세션

<beans:bean id="adminSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
<beans:property name="springSecurityContextKey" value="ADMIN_SPRING_SECURITY_CONTEXT" />
</beans:bean>

위의 관리자를 위한 스프링 시큐리티 설정에 있었던 adminSecurityContextRepository 입니다.

마치며

이와 같은 설정을 통해 우리는 애플리케이션 하나에 두 개의 인증 처리를 담았습니다. 제가 경험한 프로젝트에서는 일반 사용자용과 관리자용으로 영역을 나누어 적용을 하였지만 다른 방식으로도 유용하게 사용될 수 있을 것입니다. 예를들면, 일반적인 웹인증과 REST web service용으로 분리하여 모바일용으로도 쓸 수 있습니다.

위의 내용은 스프링 시큐리티에 관한 지식이 어느 정도는 있다는 가정하에 작성하였습니다. 다음에는 일반적인 상황을 다루되 조금더 상세하게 설명하는 시간을 갖겠습니다.

Spring 5 for Beginner
나무소리에서 제작한 Spring 5 기초 강의입니다. Spring 프레임워크의 핵심 내용과 주요 프로젝트(Spring Framework, Spring MVC, Spring Boot, Spring Data JPA)에 대해 학습합니다.