Spring Security - 기본 API 및 Filter 이해

서은경·2022년 12월 22일
0

Spring

목록 보기
32/43

모든 자료는 인프런의 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security 강의를 참고하였습니다!!!

인증 API - 스프링 시큐리티의 의존성 추가

스프링 시큐리티의 의존성 추가 시 일어나는 일들

  • 서버가 기동되면 스프링 시큐리티의 초기화 작업 및 보안 설정이 이루어진다
  • 별도의 설정이나 구현을 하지 않아도 기본적인 웹 보안 기능이 현재 시스템에 연동되어 작동한다
    • 모든 요청은 인증이 되어야 자원에 접근이 가능하다
    • 인증 방식은 폼 로그인 방식과 httpBasic 로그인 방식을 제공한다
    • 기본 로그인 페이지를 제공한다
    • 기본 계정을 한 개 제공한다 user/기본 제공 비밀번호

문제점

  • 계정 추가, 권한 추가, DB 연동 등
  • 기본적인 보안 기능 외에 시스템에서 필요로 하는 더 세부적이고 추가적인 보안기능이 필요

인증 API - 사용자 정의 보안 기능 구현

동작

❌ 시작하기에 앞서 강의에는 WebsecurityConfigurerAdapter를 상속받아 사용하지만 스프링 시큐리티 5.7에서는 더이상 지원하지 않기 때문에 상속이 아닌 bean으로 등록하여 컨테이너가 관리할 수 있도록 사용한다.

  • WebSecurityConfigurerAdapter
    : 스프링 시큐리티의 웹 보안 기능 초기화 및 설정을 관리
  • HttpSecurity
    : 세부적인 보안 기능을 설정할 수 있는 API 제공

변경 전 : 메서드를 오버라이딩해서 설정을 하고 클래스 내부에 설정 정보를 저장
변경 후 : bean으로 등록, 반환 값이 void에서 특정 타입을 리턴하도록 변경 (http.build())

예시코드

package com.test.kakaogamematch.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
// 이제 WebConfigurerAdapter를 상속받아 configure를 오버라이딩하지 않고 bean으로 관리
public class SecurityConfig {

    // 변경 전 : configure 오버라이딩
    /*@Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring().anyRequest();
                //.requestMatchers("/h2-console/**") // 인가 처리를 무시하는 url 설정
    }


     */
    // 변경 전 : configure 오버라이딩
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests()            // 요청에 대한 보안검사 시작
                .anyRequest().authenticated();      // 어떤 요청에도 인증 받음 (인가 정책)

        http
                .formLogin();                       // 기본적으로 form 로그인 방식으로 인증 설정
        return http.build();
    }
}

인증 API - Form 인증

Login

  1. Client가 Get 방식으로 자원 접근 시도
    1-1. 인증된 사용자만이 접근가능, 인증이 안되면 로그인 페이지로 리다이렉트
  2. Client가 Post 방식으로 다시 인증 시도
    2-1. 서버의 스프링 시큐리티가 세션 생성
    2-2. 최종 성공한 인증 결과를 담은 인증 토큰 생성(Authentication 타입의 클래스 객체 생성)
    2-3. 이 클래스 객체를 세션에 저장
  3. Client가 세션에 저장된 인증 토큰으로 접근/인증 유지

http.login()

.loginPage("/login.html")
: 사용자 정의 로그인 페이지
.defaultSuccessUrl("/home")
: 로그인 성공 후 이동 페이지
.failureUrl()
: 로그인 실패 후 이동 페이지
.usernameParameter
: 아이디 파라미터명 설정
.passwordParameter
: 패스워드 파라미터명 설정
.loginProcessingUrl()
: 로그인 Form Action Url
.successHandler(loginSuccessHandler())
: 로그인 성공 후 핸들러
.failureHandler(loginFailureHandler())
: 로그인 실패 후 핸들러

        http
                .formLogin()                       // 기본적으로 form 로그인 방식으로 인증 설정
                //.loginPage("/loginPage")           // 내가 설정한 로그인 페이지
                .defaultSuccessUrl("/")
                .failureUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("passwd")
                .loginProcessingUrl("/login_proc")
//                .successHandler(new AuthenticationSuccessHandler() {
//                    @Override
//                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                        System.out.println("authentication : "+authentication.getName());
//                        response.sendRedirect("/");
//                    }
//                })
//                .failureHandler(new AuthenticationFailureHandler() {
//                    @Override
//                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//                        System.out.println("exception : "+exception.getMessage());
//                        response.sendRedirect("/login");
//                    }
//                })
                .permitAll();       // loginPage에 접근하는 사용자들은 인증 제외

인증 API - Login Form 인증(2)

동작

  1. 사용자가 인증 시도
  2. UsernamePasswordAuthenticationFilter가 요청을 받아 사용자가 요청한 url 정보를 확인
  3. AntPathRequestMatcher가 현재 요청정보의 url이 login(디폴트)과 매칭되는지 확인
    3-1. 매칭되면 인증 처리
    3-2. 매칭되지 않으면 필터로 이동
  4. Authentication 객체를 만들어 객체 안에 사용자가 로그인 시 입력한 username,password를 저장하여 인증처리를 맡김
  5. AuthenticationManager(인증관리자)가 필터로부터 인증객체를 전달받아 처리를 하게됨
    5-1. AuthenticationProvider 클래스 타입의 객체들 중에 하나를 선택해 인증처리를 위임, 이 클래스가 실제로 인증처리를 담당, 성공 시 Authentication 객체를 생성해 정보 저장후 매니저에 리턴
    5-2. 인증 실패 시 AuthenticationException 예외를 발생시킴(다시 UsernamePasswordAuthenticationFilter가 받아 후속처리)
  6. Authentication 필터는 Authentication 객체(최종 성공한 인증결과=user 객체, user가 가진 권한정보를 담은 인증객체)를 전달받고 전달
    7.SecurityContext에 저장 (인증객체를 저장하는 저장소 클래스라고 보면됨, 세션에도 저장되어 사용자가 SecurityContext 안에서 Authentication 객체를 참조할 수 있도록 함)
  7. 완료! 로그인 성공 이후의 작업들을 처리함

인증 API - Logout

동작


1. Client가 로그아웃 시도
2. 스프링 시큐리티가 그 요청을 받음
2-1. 세션 무효화
2-2. 인증 토큰(인증 객체), 인증 토큰이 저장돼있는 SecurityContext 삭제
2-3. 쿠키정보 삭제
3. 로그인 페이지로 리다이렉트

http.logout()

.logoutUrl()
: 로그아웃 처리 URL
.logoutSuccessUrl()
: 로그아웃 성공 후 이동 페이지
.deleteCookies("쿠키명", "쿠키명")
: 로그아웃 후 쿠키 삭제
.addLogoutHandler(logoutHandler())
: 스프링 시큐리티가 기본적으로 제공하는 로그아웃 핸들러 구현체에서 하는 처리 외에 별도로 어떠한 처리를 하고 싶을 때 사용
.logoutSuccessHandler(logoutSuccessHandler())
: 로그아웃이 성공적으로 수행됐을 때 실행될 핸들러

http
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login")
                .addLogoutHandler(new LogoutHandler() {
                    @Override
                    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                        HttpSession session = request.getSession();
                        session.invalidate();
                    }
                })
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect("/login");
                    };
                })
                .deleteCookies("remember-me");

동작


1. logout 필터가 요청 받음
2. AntPathRequestMatcher가 검사
3. Authentication가 인증객체 담고 있는 객체를 꺼내와서 핸들러에 전달
4. SecurityContextLogoutHandler가 세션을 무효화하고 퀴를 삭제하고 SecurityContext를 삭제함, 인증 객체도 null로 처리

0개의 댓글