본문 바로가기
프로그래밍/스프링프레임워크

Srping Security 권한 직접 체크하기(시큐리티 태그와 인증 클래스)

by pentode 2018. 4. 20.

스프링 시큐리티는 롤에 따른 URL에 대한 접근제어를 기본으로 하고, 이에 관한 설정을 xml 설정 파일에 기술합니다. 전자정부표준프레임워크에서는 접근을 제어할 URL 및 ROLE 정보를 데이터베이스에서 관리할 수 있도록 커스터마이징 되어 있습니다.


메인화면 등에 로그인 여부에 따라 다른 정보를 보여 준다던가, 같은 프로그램이지만 사용자의 롤에 따라 다른 처리가 필요한 경우 직접 프로그램으로 권한을 확인해서 처리를 해야 하는 경우가 있습니다.


프로그램으로 권한 체크를 하기 위해 HttpServletRequest 객체를 사용해서 권한 정보를 얻는 것이 가능합니다. 스프링 시큐리티를 체크하는 필터가 원본 HttpServletRequest 객체를 래핑해서 기능을 추가해서 제공하기 때문입니다. 다른 방법으로는 SecurityContext 객체를 얻어서 필요한 정보를 얻는 방법이 있겠습니다. jsp 에서는 스프링 시큐리티 tag를 사용해서 필요한 권한 정보를 확인할 수 있습니다.



1. HttpServletRequest 객체를 사용하는 방법


스프링 시큐리티를 사용할때 HttpServletRequest 객체는 실제로 SecurityContextHolderAwareRequestWrapper 객체의 입니다. 스크링 시큐리티 필터가 원본 HttpServletReuest를 래핑해서 기능을 추가합니다.


Controller에서는 HttpServletRequest 객체를 메소드의 인자로 지정해 주기만 하면 쉽게 얻을 수 있습니다. 다른곳에서 사용하기 위해서는 메소드 호출시에 인자로 넘겨주던가 아니면 ContextLoader 를 사용해서 몇 단계 거쳐서 얻어야 합니다. "스프링 빈(bean) 및 서블릿(servlet) 객체 직접 얻기"  를 참조하세요.


- boolean request.isUserInRole("ROLE_ADMIN") : 인자로 주어진 롤을 가진 사용자이면 true 아니면 false를 반환 합니다.


- Principal request.getUserPrincipal() : 로그인 한 사용자 정보를 가지고 있는 객체를 반환합니다. 기본은 UserDetails 타입의 객체입니다. 전자정부표준프레임웍이라면 EgovUserDetails 타입의 객체가 반환됩니다.


- String request.getRemoteUser() :  사용자 아이디가 반환됩니다. UserDetails객체의 getUsername() 을 호출한 반환값입니다.



2. SecurityCotnext 객체를 사용하는 방법


org.springframework.security.core.context.SecurityContext 객체로부터 원하는 권한 정보를 얻을 수 있습니다.


import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;


// 시큐리티 컨텍스트 객체를 얻습니다.
SecurityContext context = SecurityContextHolder.getContext();

// 인증 객체를 얻습니다.
Authentication authentication = context.getAuthentication();

// 로그인한 사용자정보를 가진 객체를 얻습니다.
Principal principal = authentication.getPrincipal();

// 사용자가  가진 모든 롤 정보를 얻습니다.
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

Iterator<? extends GrantedAuthority> iter = authorities.iterator();

while (iter.hasNext()) {
    GrantedAuthority auth = iter.next();
    System.out.println(auth.getAuthority());
}


위의 코드를 여기 저기서 계속 사용하려면 원하는 기능을 가진 유틸리티 클래스를 하나 만들어서 사용하는 것이 좋겠습니다. 전자정부표준프레임워크에서는 이러한 기능을 가진 클래스를 제공해 줍니다.


egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper

// 로그인 사용자 정보 객체(LoginVO)
public static Object getAuthenticatedUser()

// 사용자의 롤 리스트를 얻습니다.
public static List getAuthorities()

// 로그인 여부를 확인합니다.
public static Boolean isAuthenticated()


EgovUserDetailsHelper 클래스는 final 클래스로 상속받아서 기능을 추가할 수는 없습니다. 더 많은 기능이 필요하다면 자신이 만들어서 사용해야 겠습니다.



3. 시큐리티 태그 라이브러리를 사용하는 방법


- 스프링 시큐리티 태그 라이브러리를 사용하기 위한 메이븐 의존성을 추가합니다.


전자정부표준프레임워크를 사용하고 있다면, egovframework.rte.fdl.security의 의존 라이브러리로 포함되어 있습니다.



<dependency>
  <groupId>egovframework.rte</groupId>
  <artifactId>egovframework.rte.fdl.security</artifactId>
  <version>3.6.0</version>
  <scope>compile</scope>
</dependency>


그렇지 않다면 다음을 직접 pom.xml 파일에 추가한다.


<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-taglibs</artifactId>
  <version>3.2.4.RELEASE</version>
  <scope>compile</scope>
</dependency>


- jsp 페이지에 태그 정의를 포함합니다.


<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>


- 권한을 체크하는 태그 입니다.


* 로그인 되지 않았다면 참입니다.

<sec:authorize access="isAnonymous()"></sec:authorize>


* 로그인 했다면 참입니다.

<sec:authorize access="isAuthenticated()"></sec:authorize>


* 인자로 주어진 롤을 가지고 있다면 참입니다.

<sec:authorize access="hasRole('ROLE_ADMIN')"></sec:authorize>


* 인자로 주어진 롤을 가지고 있지 않다면 참입니다.

<sec:authorize access="!hasRole('ROLE_ADMIN')"></sec:authorize>


* 인자로 주어진 롤들중 하나라도 가지고 있다면 참입니다.

<sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_MANAGER')"></sec:authorize>



만약 시큐리티 태그를 사용하고자 하는데 다음과 같은 에러가 발생할 수 있습니다.


javax.servlet.ServletException: javax.servlet.jsp.JspException: 
java.io.IOException: No visible WebSecurityExpressionHandler instance could be found in the application context.
There must be at least one in order to support expressions in JSP 'authorize' tags.


이 경우 스크링 시큐리티 설정에 WebSecurityExpressionHandler 빈을 설정하면 됩니다.


<bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />


또 다른 방법은 프링 시큐리티 설정의 <http> 요소에 user-expressions="true"를 사용하면 됩니다.


<http user-expressions="true">


이외에도 다양한 태그와 서비스 메소드에 아노테이션을 이용하여 권한을 제어할 수 있는 방법등이 있습니다.

더 자세한 사항은 스프링 시큐리티 매뉴얼을 참조하세요. 

https://docs.spring.io/autorepo/docs/spring-security/



반응형