본문 바로가기
PROGRAMING📚/Spring📑

SecuritConfig -코드 해석

Ta이니 2024. 9. 25.
728x90
반응형

 

더보기
package com.example.InstaPrj.config;

import com.example.InstaPrj.security.handler.CustomAccessDeniedHandler;
import com.example.InstaPrj.security.handler.CustomAuthenticationFailureHandler;
import com.example.InstaPrj.security.handler.CustomLoginSuccessHandler;
import com.example.InstaPrj.security.handler.CustomLogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

  // 무조건 허용하는 url
  private static final String[] AUTH_WHITElIST = {
      "/"
  };

  //
  @Bean
  PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  /* SecurityFilterChain Bean 역할 :
  세션 인증 기반 방식으로 대부분의 Spring Security에 대한 설정으로 다룰 수 있다. */
  @Bean
  protected SecurityFilterChain config(HttpSecurity httpSecurity)
      throws Exception {
    // csrf 사용안하는 설정
    httpSecurity.csrf(httpSecurityCsrfConfigurer -> {
      httpSecurityCsrfConfigurer.disable();
    });

    // authorizeHttpRequests :: 선별적으로 접속을 제한하는 메서드
    // 모든 페이지가 인증을 받도록 되어 있는 상태
    // httpSecurity.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
    httpSecurity.authorizeHttpRequests(
        auth -> auth
            .requestMatchers(AUTH_WHITElIST).permitAll()
            //.requestMatchers("/sample/all").permitAll()
            .requestMatchers(new AntPathRequestMatcher("/auth/**")).permitAll()
            .requestMatchers(new AntPathRequestMatcher("/error/**")).permitAll()
            .requestMatchers("/sample/admin/**").hasRole("ADMIN")
            .requestMatchers("/sample/manager/**").access(
                new WebExpressionAuthorizationManager(
                    "hasRole('ADMIN') or hasRole('MANAGER')")
            )
            .anyRequest().authenticated());

    // formLogin()를 정의해야만 해도 자동생성된 로그인페이지로 이동가능.
    httpSecurity.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>() {
      @Override
      public void customize(FormLoginConfigurer<HttpSecurity> httpSecurityFormLoginConfigurer) {
        httpSecurityFormLoginConfigurer
//            .loginPage("/sample/login")
//            .loginProcessingUrl("/sample/login")
//            .defaultSuccessUrl("/")
            .successHandler(getAuthenticationSuccessHandler())
            .failureHandler(getAuthenticationFailureHandler());
      }
    });
    // logout() 정의 안해도 로그아웃 페이지 사용 가능. 사용자 로그아웃 페이지 지정할 때사용
    httpSecurity.logout(new Customizer<LogoutConfigurer<HttpSecurity>>() {
      @Override
      public void customize(LogoutConfigurer<HttpSecurity> httpSecurityLogoutConfigurer) {
        httpSecurityLogoutConfigurer
            // logoutUrl() 설정할 경우 html action 주소 또한 같이 적용해야 함.
            // logoutUrl()으로 인해 기존 logout 주소 이동은 가능하나 기능은 사용 안됨.
            .logoutUrl("/logout")
            .logoutSuccessUrl("/") // 로그아웃 후에 돌아갈 페이지 설정
            .logoutSuccessHandler(getLogoutSuccessHandler())
            .invalidateHttpSession(true); // 서버 세션을 무효화, false도 클라이언트측 무효화
      }
    });
    httpSecurity.oauth2Login(new Customizer<OAuth2LoginConfigurer<HttpSecurity>>() {
      @Override
      public void customize(OAuth2LoginConfigurer<HttpSecurity> httpSecurityOAuth2LoginConfigurer) {
        httpSecurityOAuth2LoginConfigurer.successHandler(
            getAuthenticationSuccessHandler()
        );
      }
    });
    httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
        httpSecurityExceptionHandlingConfigurer.accessDeniedHandler(
            getAccessDeniedHandler());
    });
    httpSecurity.rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
      @Override
      public void customize(RememberMeConfigurer<HttpSecurity> httpSecurityRememberMeConfigurer) {
        // database 아이디를 통하여 로그인하는 경우 사용, 소셜로그인은 사용 불가
        httpSecurityRememberMeConfigurer.tokenValiditySeconds(60 * 60 * 24 * 7);
        // 익명객체를 활용하여 rememberMe 사용할 때
        /*httpSecurityRememberMeConfigurer.rememberMeServices(new RememberMeServices() {
          @Override
          public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
            return null;
          }

          @Override
          public void loginFail(HttpServletRequest request, HttpServletResponse response) {

          }

          @Override
          public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {

          }
        });*/
      }
    });

    return httpSecurity.build();
  }
  // AuthenticationSuccessHandler는 로그인되었을 때 처리하는 객체
  @Bean
  public AuthenticationSuccessHandler getAuthenticationSuccessHandler() {
    return new CustomLoginSuccessHandler();
  }

  @Bean
  public AccessDeniedHandler getAccessDeniedHandler() {
    return new CustomAccessDeniedHandler();
  }

  @Bean
  public AuthenticationFailureHandler getAuthenticationFailureHandler() {
    return new CustomAuthenticationFailureHandler();
  }

  @Bean
  public LogoutSuccessHandler getLogoutSuccessHandler() {
    return new CustomLogoutSuccessHandler();
  }

  // InMemory 방식으로 UserDetailsService(인증 관리 객체) 사용
  /*@Bean
  public UserDetailsService userDetailsService() {
    UserDetails user1 = User.builder()
        .username("user1")
        .password("$2a$10$XGw3jOo9mQSoij4/so.6H.BtSRWpgPze6ZWMuc7ntyFFWqVNbcmBe")
        .roles("USER")
        .build();
    UserDetails manager = User.builder()
        .username("manager")
        .password("$2a$10$AEHcuzENZx7OLeA.s8e.t.CvhE/a/GZf.ZKTPEBIKLv8g03zChnD2")
        .roles("MANAGER")
        .build();
    UserDetails admin = User.builder()
        .username("admin")
        .password(passwordEncoder().encode("1"))
        .roles("ADMIN", "MANAGER")
        .build();
    List<UserDetails> list = new ArrayList<>();
    list.add(user1);
    list.add(manager);
    list.add(admin);
    return new InMemoryUserDetailsManager(list);

  }*/

}

이 코드는 Spring Boot에서 Spring Security 설정을 관리하는 SecurityConfig 클래스입니다. 이 클래스는 애플리케이션의 보안 설정을 정의하고, 인증 및 권한 부여를 처리하는 중요한 역할을 합니다. 코드를 단계별로 해석해 드리겠습니다.


1. 클래스 선언과 애너테이션

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
  • @Configuration: 이 클래스가 스프링 컨텍스트에서 설정 파일로 인식되도록 합니다.
  • @EnableWebSecurity: 이 애너테이션은 Spring Security의 웹 보안을 활성화합니다.
  • @EnableMethodSecurity: 메서드 수준에서 보안을 활성화합니다. 특정 메서드에 권한을 설정하거나 제한을 둘 수 있습니다.

2. 허용된 URL 정의 (화이트리스트)

private static final String[] AUTH_WHITElIST = {
    "/"
};
  • AUTH_WHITElIST: 인증 없이 접근할 수 있는 URL 목록을 정의합니다. 여기서는 루트 경로("/")만 인증 없이 접근이 가능합니다.

3. 비밀번호 인코더 설정

@Bean
PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
  • BCryptPasswordEncoder: 비밀번호를 암호화하는 데 사용되는 인코더입니다. BCrypt는 단방향 해시 함수로, 비밀번호를 안전하게 암호화하여 데이터베이스에 저장할 수 있게 합니다.

4. SecurityFilterChain 설정

@Bean
protected SecurityFilterChain config(HttpSecurity httpSecurity) throws Exception {
  • SecurityFilterChain: 스프링 시큐리티에서 필터 체인을 설정하는 객체입니다. 이 필터 체인을 통해 HTTP 요청이 처리되는 방식을 정의합니다.

5. CSRF 비활성화

httpSecurity.csrf(httpSecurityCsrfConfigurer -> {
    httpSecurityCsrfConfigurer.disable();
});
  • CSRF(Cross-Site Request Forgery): 사이트 간 요청 위조 방지를 위한 보안 기능입니다. 여기서는 CSRF 보호를 비활성화합니다.

6. HTTP 요청 권한 설정

httpSecurity.authorizeHttpRequests(
    auth -> auth
        .requestMatchers(AUTH_WHITElIST).permitAll()
        .requestMatchers(new AntPathRequestMatcher("/auth/**")).permitAll()
        .requestMatchers(new AntPathRequestMatcher("/error/**")).permitAll()
        .requestMatchers("/sample/admin/**").hasRole("ADMIN")
        .requestMatchers("/sample/manager/**").access(
            new WebExpressionAuthorizationManager(
                "hasRole('ADMIN') or hasRole('MANAGER')")
        )
        .anyRequest().authenticated());
  • authorizeHttpRequests: 각 URL 경로에 대한 접근 권한을 설정합니다.
    • /auth/**, /error/**, /모든 사용자에게 접근 허용 (permitAll()).
    • /sample/admin/**ADMIN 역할을 가진 사용자만 접근 가능 (hasRole("ADMIN")).
    • /sample/manager/**ADMIN 또는 MANAGER 역할을 가진 사용자만 접근 가능.
    • 그 외 모든 요청(anyRequest())은 인증된 사용자만 접근 가능합니다.

7. 폼 로그인 설정

httpSecurity.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>() {
    @Override
    public void customize(FormLoginConfigurer<HttpSecurity> httpSecurityFormLoginConfigurer) {
        httpSecurityFormLoginConfigurer
            .successHandler(getAuthenticationSuccessHandler())
            .failureHandler(getAuthenticationFailureHandler());
    }
});
  • 폼 로그인 설정: 사용자가 로그인할 때 사용하는 폼 설정을 정의합니다.
    • 성공 시: getAuthenticationSuccessHandler()가 호출됩니다.
    • 실패 시: getAuthenticationFailureHandler()가 호출됩니다.

8. 로그아웃 설정

httpSecurity.logout(new Customizer<LogoutConfigurer<HttpSecurity>>() {
    @Override
    public void customize(LogoutConfigurer<HttpSecurity> httpSecurityLogoutConfigurer) {
        httpSecurityLogoutConfigurer
            .logoutUrl("/logout")
            .logoutSuccessUrl("/")
            .logoutSuccessHandler(getLogoutSuccessHandler())
            .invalidateHttpSession(true);
    }
});
  • 로그아웃 설정: 로그아웃 시 처리 방식을 정의합니다.
    • 로그아웃 URL: /logout을 통해 로그아웃.
    • 성공 후 이동할 URL: 로그아웃 후 루트 경로(/)로 리다이렉트.
    • 세션 무효화: 로그아웃 시 세션을 무효화 (invalidateHttpSession(true)).

9. OAuth2 로그인 설정

httpSecurity.oauth2Login(new Customizer<OAuth2LoginConfigurer<HttpSecurity>>() {
    @Override
    public void customize(OAuth2LoginConfigurer<HttpSecurity> httpSecurityOAuth2LoginConfigurer) {
        httpSecurityOAuth2LoginConfigurer.successHandler(
            getAuthenticationSuccessHandler()
        );
    }
});
  • OAuth2 로그인 설정: 소셜 로그인을 설정하며, 성공 시 getAuthenticationSuccessHandler()가 호출됩니다.

10. 예외 처리 핸들러 설정

httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
    httpSecurityExceptionHandlingConfigurer.accessDeniedHandler(
        getAccessDeniedHandler());
});
  • 권한 예외 처리: 사용자가 권한이 없는 페이지에 접근할 때 getAccessDeniedHandler()가 호출되어 처리됩니다.

11. Remember-Me 기능 설정

httpSecurity.rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
    @Override
    public void customize(RememberMeConfigurer<HttpSecurity> httpSecurityRememberMeConfigurer) {
        httpSecurityRememberMeConfigurer.tokenValiditySeconds(60 * 60 * 24 * 7);
    }
});
  • Remember-Me 기능: 로그인 세션이 만료된 후에도 사용자가 기억되도록 하는 기능.
    • 유효 기간: 7일(60 * 60 * 24 * 7).

12. 핸들러 클래스들

  • AuthenticationSuccessHandler: 로그인 성공 시 동작을 정의하는 핸들러입니다.
    • CustomLoginSuccessHandler: 로그인 성공 후 처리할 동작을 정의한 사용자 정의 핸들러.
  • @Bean public AuthenticationSuccessHandler getAuthenticationSuccessHandler() { return new CustomLoginSuccessHandler(); }
  • AccessDeniedHandler: 권한이 없을 때 호출되는 핸들러입니다.
  • @Bean public AccessDeniedHandler getAccessDeniedHandler() { return new CustomAccessDeniedHandler(); }
  • AuthenticationFailureHandler: 로그인 실패 시 동작을 정의하는 핸들러입니다.
  • @Bean public AuthenticationFailureHandler getAuthenticationFailureHandler() { return new CustomAuthenticationFailureHandler(); }
  • LogoutSuccessHandler: 로그아웃 성공 시 동작을 정의하는 핸들러입니다.
  • @Bean public LogoutSuccessHandler getLogoutSuccessHandler() { return new CustomLogoutSuccessHandler(); }

요약

이 코드는 Spring Security의 핵심 설정을 관리하며, 사용자 인증, 권한 부여, 로그인/로그아웃 처리 및 예외 처리 등을 담당합니다. 각 요청에 대해 인증 및 권한을 설정하고, 다양한 핸들러를 통해 성공 및 실패 시 맞춤형 동작을 정의하는 구조입니다.

728x90
반응형

댓글