용어
•
접근 주체(Principal) : 보호된 대상에 접근하는 유저
•
인증(Authenticate) : 현재 유저가 누구인지 확인(ex. 로그인)
◦
애플리케이션의 작업을 수행할 수 있는 주체임을 증명
•
인가(Authorize) : 현재 유저가 어떤 서비스, 페이지에 접근할 수 있는 권한이 있는지 검사
•
권한 : 인증된 주체가 애플리케이션의 동작을 수행할 수 있도록 허락되있는지를 결정
◦
권한 승인이 필요한 부분으로 접근하려면 인증 과정을 통해 주체가 증명 되어야만 한다
◦
권한 부여에도 두가지 영역이 존재하는데 웹 요청 권한, 메소드 호출 및 도메인 인스턴스에 대한 접근 권한 부여
스프링 시큐리티 설정 → 자바파일
SecurityConfiguration
•
pom.xml에서 시큐리티 사용하도록
•
unauthorizedEntryPoint 설정
•
configure(HttpSecurity http) throws Exception {}
◦
??? 얘는 뭐하는 놈일까
•
configure(WebSecurity web) throws Exception{}
◦
resource 파일들은 전부 허용한다.
•
web.xml
◦
스프링 시큐리티 관련 필터 클래스 등록
◦
sprintSecurityFilterChain을 구현 → 자바 설정파일에 의해 DI 컨테이너에 빈으로 등록
◦
서블릿 필터의 이름으로 DI 컨테이너에서 관리되는 빈의 이름을 지정하고
◦
DelegatingFilterProxy를 사용해서 서블릿 필터(FilterChainProxy) 클래스를 서블릿 컨테이너에 등록
스프링 시큐리티 아키텍쳐
스프링 시큐리티의 모듈 구성
•
spring-security-core : 인증(Authentication), 인가(Authorization)을 구현
•
spring-security-web : 웹 애플리케이션의 보안 기능을 구현
•
spring-security-config : 각 모듈에서 제공하는 컴포넌트의 설정
•
spring-scurity-taglibs : 인증 정보나 인가 정보를 사용하기 위한 JSP 태그 라이브러리
프레임워크 아키텍처
•
기본적으로 스프링 시큐리티는 클라이언트와 웹 어플리케이션 소스 사이를 가로막고 있다
•
FilterChainProxy : 요청을 받은 다음 HttpFireWall 인터페이스의 메서드를 호출해서 HttpServletRequest와 HttpServletResponse에 대한 방화벽 기능
•
이후 SecurityFilterChain에 설정되어있는 시큐리티 필터 클래스에 처리를 위임
•
SecurityFilterChain에는 여러 보안 필터가 연쇄적으로 연결, 앞에꺼가 끝나면 그 다음꺼 하는 식으로
•
만약에 다 끝나면 리소스에 접근해서 처리하고 반환 클라이언트에 전달
SecurityFilterChain : FilterChainProxy가 받은 요청에 적용할 보안 필터 목록을 관리하기 위한 인터페이스
기본적으로 DefaultSecurityFilterChain클래스가 사용되고 요청 패턴별로 보안 필터 목록을 관리
얘를 들어 SeucurityConfiguration 파일을
@EnableWebSecurity
public class WebSecurityConfg{
@configuration
@order(1)
public static class UiWebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure() throws Exception{
http.antMatcher("/ui/**");
}
}
@Configuration
@Order(2)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure() throws Exception{
http.antMatcher("/api/**");
}
}
}
Java
복사
이렇게 설정하면 지정한 경로마다 다른 보안필터를 적용가능함
보안 필터
보안기능을 제공하는 서블릿 필터 클래스
이러한 보안 필터를 체인 형태로 연결해서 웹 어플리케이션 보안기능을 하도록 만들어짐
핵심 필터
•
SecurityContextPersistenceFilter : 인증 정보를 요청 처리 과정 전반에서 공유할 수 있도록, 기본 구현에서는 HttpSession에 인증 정보를 저장해서 공유하는 방식을 사용
•
UsernamePasswordAuthenticationFilter : 요청 파라미터에서 지정한 사용자명과 패스워드를 사용해 인증을 처리, 폼 인증을 수행할 때 사용
•
LogoutFilter : 로그아웃 처리
•
FilterSecurityInterceptor : HTTP요청의 인가를 처리
•
ExceptionTranslationFilter : FilterSecurityInterceptor에서 발생한 예외를 처리하고 클라이언트에 반환할 응답을 생성
인증 처리
인증하는데 있어서 여러 방법이 존재한다
HTML입력 폼, RFC에서 정해진 HTTP표준 인증 방식, OpenID인증이나 싱글 사이온 인증 등등
매커니즘
클라이언트
Authentication Filter
Authentication Manager ←구현— Provider Manager
Authentication Provider ←구현— Dao Authentication Provider
//spring-security-web
인증 필터(Authentication Filter) : 인증 처리 방식에 대한 구현을 제공하는 서블릿 필터
폼 인증용 → UsernamePasswordAuthenticationFilter 이외에도 Basic, Digest, RememberMe 등등
// spring-security-core
AuthenticationManager : 인증 처리를 위한 인터페이스, 기본 구현(ProviderManager)에서는 실제 인증 처리를 AuthenticationProvider에 위임하고 반환되는 인증 결과를 처리하는 구조
AuthenticationProvider : 인증 처리 기능을 구현하기 위한 인터페이스, 사용자의 자격정보와 상태 정보를 확인하기 위해 DaoAuthenticationProvider를 사용하는 것을 전제로 설명
폼 인증
클라이언트 요청
UsernamePasswordAuthenticationFilter
AuthenticationManager
이후 Authentication SuccessHandler, Authentication FailureHandler
UsernamePasswordAuthenticationFilter : 요청 파라미터에서 자격 정보를 구한 다음, Authentication Manager를 통해 해당 이용자가 인증된 사용자인지 확인
인증 결과를 보고 성공 시 → successHandler, 실패시 failureHandler
폼 인증 하려면 아래와 같이 빈을 설정해줘야한다.
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin();
}
}
Java
복사
이후 해야할 것 → 로그인 폼을 작성하는 것
로그인 폼에 필요한 것 : 인증 오류를 표시하기 위한 영역, 사용자명과 패스워드를 입력하기 위한 로그인 폼
이 로그인 폼을 반환하기 위한 handler, Controller를 작성
컨트롤러까지 작성하고 나면 뭘 자바 빈 설정 파일을 수정해야함
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin()
.loginPage("/login") /* loginPage 메서드를 호출할 때, 로그인 폼을 표시하기 위한 경로를 지정*/
.permitAll(); /* 모든 이용자가 로그인 폼에 접근할 수 있도록*/
http.authorizeRequests()
.anyRequest().authenticated();
}
}
Java
복사
커스터마이징
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin()
.loginProcessingUrl("/authenticate") /* loginPage 메서드를 호출할 때, 로그인 폼을 표시하기 위한 경로를 지정*/
.username("uid");
.useserpassword("pwd");
.defaultSuccessUrl("/menu");
.failureUrl("/loginFailure");
.permitAll(); /* 모든 이용자가 로그인 폼에 접근할 수 있도록*/
http.authorizeRequests()
.anyRequest().authenticated();
}
}
Java
복사
데이터베이스 인증
AuthenticationFilter →
Provider Manager → Dao Authentication Provider : UserDetails와 클라이언트의 인증 정보를 대조
UserDetails 인터페이스
1.
사용자명 & 패스워드
2.
계정의 잠금 상태와 유효 기간 상태를 판단
3.
자격 정보의 유효기간 상태
4.
사용자가 가진 권한 리스트를 반환
로그아웃
@Override
protected void configure(HttpSecurity http) throws Exception{
http.logout()
.logoutSuccessUrl("/logoutSuccees")
.permitAll();
// 로그 아웃 처리
}
Java
복사
인증 정보에 대한 접근
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String userUid = null;
if(authenticaiton.getPrincipal() instanceof AccountUserDetails){
AccountUserDetails userDetails =
AccountUserDetails.class.cast(authentication.getPrincipal());
userUid = userDetails.getAccount().getUserUid();
}
Java
복사
인증된 사용자의 인증 정보는 기본 구현에서는 세션에 저장됨
세션에 저장된 인증 정보는 요청마다 SecurityContextPersistenceFilter에 의해서 SecurityContextHolder라는 클래스에 저장되어 같은 스레드에서 실행되고 있다면 소스코드의 어디서든 인증 정보를 접근할 수 있다.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<sec:authentication property="principal.account.lastName"/>
HTML
복사
인가 처리 구조
클라이언트
Exception TranslationFilter
FilterSecurityInterceptor
리소스
FilterSecurityInterceptor
AccessDecisionManager ←구현— Affirmative Based
Affirmative Based
. AccessDecisonVoter ←구현— Web Expression Voter
Exception TranslationFilter: 인가 과정에서 발생한 예외를 처리하고 클라이언트에 적절한 응답을 하기 위한 서블릿 필터. 인증되지 않은 사용자가 접근할 경우 인증 페이지를 표시해서 로그인을 유도하고, 인증된 사용자이긴 하나 해당 리로스에 접근 권한이 없는 경우에는 인증 오류를 통지하는 응답을 반환
FilterSecurityInterceptor: Http요청에 대한 인가 처리를 적용하기 위한 서블릿 필터, 실제 인가 처리는 AccessDecisionManager에 위임. AccessDecisonManager의 메서드를 호출할 때는 클라이언트가 접근하려고 한 웹 리소스의 접근 정책을 연계해야함
AccessDecisonManager: 접근하려고 하는 리소스에 대한 접근 권한이 있는 검사하는 인터페이스
기본 구현에서는 AccessDecisionVoter라는 인터페이스의 메서드를 호출해서 접근 권한을 부여할지 투표 받는 구조. 이 때 사용되는 구현 클래스는 Affirmative Based 단 하나의 AccessDecisionVoter 라도 '부여'로 투표하면 접근 권한을 부여하는 구현 클래스
AccessDecisionVoter: 접근하려고 하는 리소스에 대한 접근 정책을 참조해서 접근 권한을 부여할지 여부를 투표하는 인터페이스. 기본적으로 WebExpressionVoter가 기본 적용되도록 통일
접근 정책을 기술하는 법
접근 정책을 지정할 때 스프링 표현언어를 사용할 수 있다.