스프링 시큐리티는 스프링 기반의 어플리케이션의 보안(인증과 권한)을 담당하는 프레임워크이다.
만약 스프링 시큐리티를 사용하지 않았다면, 자체적으로 세션을 체크하고 리다이렉트 등을 해야 한다.
스프링 시큐리티는 보안과 관련해서 체계적으로 많은 옵션들을 지원해준다.
스프링 시큐리티는 필터(Filter) 기반으로 동작하기 때문에 스프링 MVC 와 분리되어 관리 및 동작합니다.
웹사이트는 각종 서비스를 하기 위한 리소스와 서비스를 사용하는 유저들의 개인 정보를 가지고 있습니다. 이들 리소스를 보호하기 위해서 일반적으로 웹 사이트는 두가지 보안 정책을 설정해야 합니다.

스프링 시큐리티가 관심을 가지고 있는걸 크게 두가지로 나눈다면 하나는 인증이고 하는 권한이다.
사이트에 접근하는 사람이 누구인지 시스템이 알아야 합니다. 익명사용자(anonymous user)를 허용하는 경우도 있지만, 특정 리소스에 접근하거나 개인화된 사용성을 보장 받기 위해서는 반드시 로그인하는 과정이 필요합니다. 로그인은 보통 username / password 를 입력하고 로그인하는 경우와 sns 사이트를 통해 인증을 대리하는 경우가 있습니다.
전통적인 사이트들은 누가 로그인 했는지에 대한 정보를 가지는 세션을 이용했었지만 최근에는 여러대의 서버로 서비스하는 경우가 많기때문에 세션을 서로 분리해서 저장하고 동기화하기 때문에 토큰방식을 쓰는 경우가 많다.
사용자가 누구인지 알았다면 사이트 관리자 혹은 시스템은 로그인한 사용자가 어떤 일을 할 수 있는지 권한을 설정합니다. 권한은 특정 페이지에 접근하거나 특정 리소스에 접근할 수 있는 권한여부를 판단하는데 사용됩니다. 개발자는 권한이 있는 사용자에게만 페이지나 리소스 접근을 허용하도록 코딩해야 하는데, 이런 코드를 쉽게 작성할 수 있도록 프레임워크를 제공하는 것이 스프링 시큐리티 프레임워크(Spring Security Framework) 입니다.
권한을 체크하는 것을 Authorization이라고 한다. 권한은 어노테이션으로 체크를 한다. 비즈니스 로직이 복잡해지면 어노테이션으로 하기 어렵다 이런경우 AOP를 이용해서 권한 체크를 하는경우도 있다. 비즈니스가 복잡해질수록 다양한 방법이 있을 수 있다.
간단히 특정된 소스를 위한 서비스나 테스트를 위해 사용하는 용도로 사용합니다. 스프링 시큐리티를 테스트 하기 위한 용도로 사용합니다.
스프링 시큐리티가 설정되면 서버가 만들어놓은 패스워드를 가지고 접근해야한다. 이런경우 기억하기 어렵기 때문에 yml 에서 아래와 같이 설정하면 쉽게 이용가능하다.
spring.security.user:
name:user1
paswword:1111
roles:USER
톰캣과 같은 웹 애플리케이션을 서블릿 컨테이너라고 부르는데,(서버가 여러개의 서블릿들을 담고 있기 때문이다.) 이런 웹 애플리케이션(J2EE Application)은 기본적으로 필터와 서블릿으로 구성되어있다.

컨트롤러의 메소드에 URL을 매핑을 해서 웹 리퀘스트가 그 메소드를 찾아가게 하는 방법은 바로 dispathcServlet때문인데, dispathcServlet은 등록된 컨트롤러와 메소드들에서 URL과 매칭이 되는 메소드를 찾아서 실행시켜주는 역할을 한다.
필터는 세션을 매칭시켜 준다거나, 인코딩을 맞춰준다거나 등등 모든 리퀘스트에 대해서 공통적으로 동작해야 하는것들을 주로 필터에 위치시키게된다.
필터들은 체인으로 엮어 있기때문에 리퀘스트가 서블릿의 메소드에 도착하려면 반드시 필터를 하나하나 거쳐야한다.
하지만 시큐리티의 경우에는 여러가지 정책이 존재할 수 있다. 필터체인에 여러정책이 하나로 묶여 들어가면 문제가 생긴다. 중간의 프록시를 통해서 선택적으로 필터체인을 스위칭해가면서 사용해야 한다. 그래서 스프링 시큐리티는 DelegatingFilterProxy 라는 필터를 만들어 메인 필터체인에 끼워넣고, 그 아래 다시 SecurityFilterChain 그룹을 등록한다.


시큐리티 필터체인에 어떤 필터들을 넣을수있는가 ? 하는것이 시큐리티의 가장 큰 부분이기도 하다 스프링 시큐리티 라이브러리가 제공해주는 라이브러리가 많고, 대부분의 필터는 각각 다른 관심사를 필터링한다.
그 밖에... OAuth2 나 Saml2, Cas, X509 등에 관한 필터들도 있다.
스프링 프레임워크에서 로그인을 한다는 것은 authenticated 가 true인 Authentication 객체를 SecurityContext 에 갖고 있는 상태를 말합니다. 단 Authentication이 AnonymousAuthenticationToken 만 아니면 됩니다.
로그인 == Authentication(authenticated = true)
only if Authentication != AnonymousAuthenticationToken
인증은 '증명하다'라는 의미로 예를 들어, 유저 아이디와 비밀번호를 이용하여 로그인 하는과정 을 말합니다.

스프링 시큐리티에서 Authentication은 Authorization으로 구성이 된다. 필터들 중에 일부 필터는 인증 정보에 관여한다. 이들 필터가 하는 일은 AuthenticationManager 를 통해 Authentication 을 인증하고 그 결과를 SecurityContextHolder 에 넣어주는 일입니다.

스프링 시큐리티에서 로그인을 하는 것은 Authentication을 제공(Provide)하는 AuthentificationProvider(인증제공자)는 한 개이상 존재할 수 있고, AuthentificationProvider를 관리하는 인터페이스 AuthentificationManager를 구현하고 있는 구현체는 providerManager도 인증방식에 따라 복수로 존재 할 수 있다. 페어런트 구조로 레퍼런스를 하고 있는 구조를 띄고 있다,
Set<GrantedAuthority> authorities : 인증된 권한 정보principal : 인증 대상에 관한 정보. 주로 UserDetails 객체가 옴credentials : 인증 확인을 위한 정보. 주로 비밀번호가 오지만, 인증 후에는 보안을 위해 삭제함.details : 그 밖에 필요한 정보. IP, 세션정보, 기타 인증요청에서 사용했던 정보들.boolean authenticated : 인증이 되었는지를 체크함.굳이 Authentication에 넣어놓은 이유는 SecurityContext holder로 데이터가 들어가게 되면 컨트롤러 안이나 서비스 안에서 정보를 접근하게 되는데 이 경우 Request 객체에서 접근할 수 있는 값들이 필요한 경우에는 불필요하게 HTTP 서블릿 리퀘스트를 서비스까지 끌고 들어가야 하는걸 방지하기 위해서이다.
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Logging out [%s]", auth));
}
this.handler.logout(request, response, auth);
this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
LogoutHandler
- void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication);
- SecurityContextLogoutHandler : 세션과 SecurityContext 를 clear 함.
- CookieClearingLogoutHandler : clear 대상이 된 쿠키들을 삭제함.
- CsrfLogoutHandler : csrfTokenRepository 에서 csrf 토큰을 clear 함.
- HeaderWriterLogoutHandler
- RememberMeServices : remember-me 쿠키를 삭제함.
- LogoutSuccessEventPublishingLogoutHandler : 로그아웃이 성공하면 이벤트를 발행함.
LogoutSuccessHandler
- void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException;
- SimpleUrlLogoutSuccessHandler
https://gitlab.com/jongwons.choi/spring-boot-security-lecture/-/blob/master/part0/2%20%EC%8A%A4%ED%94%84%EB%A7%81%20%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%EB%9E%80.md?ref_type=heads
https://m.boostcourse.org/web326/lecture/58997