본문 바로가기

개인공부

SpringSecurity 정리 및 샘플코드

반응형

SpringSecurity란?

Spring Security는 Spring 기반의 애플리케이션의 보안(인증과 권환, 인가 등)을 담당하는 스프링 하위 프레임워크이다. Spring Security는 '인증'과 '권한'에 대한 부분을 Filter 흐름에 따라 처리하고 있다. Filter는 Dispatcher Servlet으로 가기 전에 적용되므로 가장 먼저 URL 요청을 받지만, Intercepteor는 Dispatcher와 Controller 사이에 위치한다는 점에서 적용 시기의 차이가 있다. Spring Security는 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 개발자 입장에서는 일일이 보안관련 로직을 작성하지 않아도 된다는 장점이 있다.

인증관련 architecture

 

의존성

		<!-- Spring Security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

 

Config 설정

@Configurable
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // spring Security에서 제공하는 여러 설정등 을 할 수있다.
    // 기본적으로 제공하는 스프링 시큐리티 필터들을 설정한다.
}

Configure

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.mvcMatchers("/","/info","/account/**","/signup").permitAll()
			.mvcMatchers("admin").hasRole("ADMIN")
			.mvcMatchers("user").hasRole("USER")
			.anyRequest().authenticated()
			.expressionHandler(expressionHandler());
		http.formLogin().loginPage("/login").permitAll()
			.and()
		.httpBasic();

mbcMatcher를 이용해서 url경로에 따른 인증권한을 부여한다.

permitAll() 해당 URL은 인증이 필요없음

hasRole 특정 조건의 권한만 사용할 수 있음

anyRequest 그밖의 URL

authenticated 인증이 필요함

 

SecurityExpressionHandler

	public SecurityExpressionHandler expressionHandler() {
		RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
		roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");

		DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
		handler.setRoleHierarchy(roleHierarchy);

		return handler;
	}

권한에 대한 룰을 적용한다 여기서는 ADMIN의 권한은 USER에 권한을 포함한다는 것

 

세션을 사용하지 않음

http.sessionManagement()
			.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

Form 기반에 대해서는 당연히 세션을 이용해서 인증권한을 유지해주면 좋겠지만 REST API의 경우에는 세션을 유지하는게 의미가 없다. 따라서 세션권한을 STATELESS로 사용하면 세션을 유지하지않는다. (REST API 구현시 필요할 것 같음)

 

SecurityFilterChain

Security와 관련한 서블릿 필터도 실제로는 연결된 여러 필터들로 구성 되어 있습니다. 이러한 모습때문에 Chain(체인)이라는 표현을 쓰고 있습니다. 해당 필터들의 역할과 흐름을 알고 있어야 필터의 커스터마이징을 진행 할 수 있습니다.

필터의 종류


SecurityContextPersistenceFilter - 요청(request)전에, SecurityContextRepository에서 받아온 정보를 SecurityContextHolder에 주입합니다.

LogoutFilter - 주체(Principal)의 로그아웃을 진행합니다. 주체는 보통 유저를 말합니다.

UsernamePasswordAuthenticationFilter - (로그인) 인증 과정을 진행합니다.

DefaultLoginPageGeneratingFilter - 사용자가 별도의 로그인 페이지를 구현하지 않은 경우, 스프링에서 기본적으로 설정한 로그인 페이지를 처리합니다.

BasicAuthenticationFilter - HTTP 요청의 (BASIC)인증 헤더를 처리하여 결과를 SecurityContextHolder에 저장합니다.

RememberMeAuthenticationFilter - SecurityContext에 인증(Authentication) 객체가 있는지 확인하고RememberMeServices를 구현한 객체의 요청이 있을 경우, Remember-Me(ex 사용자가 바로 로그인을 하기 위해서 저장 한 아이디와 패스워드)를 인증 토큰으로 컨텍스트에 주입합니다.

AnonymousAuthenticationFilter - SecurityContextHolder에 인증(Authentication) 객체가 있는지 확인하고, 필요한 경우 Authentication 객체를 주입합니다.

SessionManagementFilter - 요청이 시작된 이 후 인증된 사용자 인지 확인하고, 인증된 사용자일 경우SessionAuthenticationStrategy를 호출하여 세션 고정 보호 메커니즘을 활성화하거나 여러 동시 로그인을 확인하는 것과 같은 세션 관련 활동을 수행합니다.

ExceptionTranslationFilter - 필터 체인 내에서 발생(Throw)되는 모든 예외(AccessDeniedException, AuthenticationException)를 처리합니다.

FilterSecurityInterceptor - HTTP 리소스의 보안 처리를 수행합니다.

 

디버깅 모드로 언제 동작하는지 찍어보자

Authentication

최초 root로 접속시 Authentication 에 값이 ROLE_ANONYMOUS 인것을 확인 하였다.
principal 이라는 값 이 있는데 이값은 null 인 상태이다.
아마 로그인 (인증)을 하면 Principal 값이 null이 아닌값으로 바뀔것 같다.

 

인증 후에는 Principal 값이 ROLE_USER 로 바뀌어 있었다..

 

Filter가 어떻게 돌아가는 궁금해서 filterChainProxy 검색

Break Point를 찍고 "/" 경로를 탐색해보니 여러 필터들이 생성된것을 볼 수 있다.
(Spring Security 설정에 따라 필터들의 수가 달라지다고 한다.)

 

"/" 접속시 

여러필터들이 등록되어 있는것을 확인 할 수 있다.
저중에서 매치가 되는 필터들을 return한다.
저렇게 내부적으로 for 문을 돌면서 해당 필터체인에 mach가 되면 return을 하게되는 구조다. (null값이면.. 필터에 걸리지 않은것 같다

 

accessDecisionManager

필터들이 돌면서 허가되지 않은 인증에대해서는 accessDecisionManager가 예외처리가 된다.
"/" 루트권한에대해서는 try문을 실행하고 토큰을 받는 것을 확인 했다.

 

"user"권한에 필요한 url에 접속시

예외를 처리하고 권한 인증이 필요한 /login url을 호출 한다 (이때 프록시 필터가 /login 권한에 대해서 한번더 체크하는것을 확인)

user로 접속 후 에는 accessDecisionManager 가 예외를 처리하지 않고 user화면을 뛰운다.

 

user 권한으로 admin 권한을 접속시 다시한번더 accessDecisionManager 예외를 처리하면서 이동을 한다.

 

정리

SpringSecurity를 사용한다면 모든 요청은 FilterChainProxy를 거치게 된다.
FilterChainProxy에서 특정한 요청의 경우 우선순위와 URLPattern에 해당하는 SecurityChain을 찾아 해당 Chain의 Filter들을 가져와 이를 실행한다.
SecurityConfig가 하나의 SecurityChain이며, 다수의 설정이 존재할 경우 반드시 우선순위를 지정해야한다.
반응형

'개인공부' 카테고리의 다른 글

REST API / Spring hateoas  (0) 2020.10.04
CSRF, CORS 개념  (0) 2020.10.04
SpringSecurity 패스워드 암호화(bcrypt)  (0) 2020.10.04
Mybatis VS Hibernate  (0) 2020.10.04
git flow, git hub flow , git lab flow  (0) 2020.10.04