부트캠프 기록/Section4

[Spring Security] Spring Security 개요1

bbangduck 2022. 11. 19. 19:22

Spring Security란

Spring MVC 기반 애플리케이션의 인증(Authentication)과 인가기능(Authorization)을 지원하는 보안 프레임워크

Spring 에서 지원하는 Interceptor나 Servlet Filter를 이용해 직접 보안 기능을 구현할 수 있지만 웹 애플리케이션 보안 대부분의 기능을 Spring Security에서 안정적으로 지원하고 있기 때문에 Spring Security를 이용하는 것이 안전한 선택

 

  • 다양한 유형의 사용자 인증 기능 적용
    • 폼 로그인 인증
    • 토큰 기반 인증
    • OAuth 2 기반 인증
    • LDAP 인증

 

  • 애플리케이션 사용자의 역할에 따른 권한 레벨 적용 
  • 애플리케이션에서 제공하는 리소스에 대한 접근 제어
  • 민감한 정보에 대한 데이터 암호화
  • SSL 적용
  • 일반적으로 알려진 웹 보안 공격 차단

 

 

Spring Security를 사용해야 하는 이유

  • 보안 기능을 밑바닥부터 직접 구현하는 것보다 잘 검증되어 신뢰할 만한 Spring Security를 사용하는 것이 더 나은 선택이다.
  • Spring Security는 특정 보안 요구 사항을 만족하기 위한 커스터마이징이 용이하고, 유연한 확장이 가능하다.

 

 


SSR 방식 Spring Security의 기본 구조(1)

1. 의존 추가

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-security'   // (1)
}

 

Spring Security에서 디폴트 로그인 정보 제공

Username : user

Password는 애플리케이션이 실행할때 마다 출력되는 로그에서 확인 가능

 

 

2. Spring Security Configuration 적용

@Configuration

 

3. InMemory User로 인증하기 

  @Bean
    public UserDetailsManager userDetailsService() {
        // (1)
        UserDetails userDetails =
                User.withDefaultPasswordEncoder()    // (1-1)
                        .username("bbangduck@gmail.com") // (1-2)
                        .password("1111")            // (1-3)
                        .roles("USER")               // (1-4)
                        .build();
        // (2)
        return new InMemoryUserDetailsManager(userDetails);

 

InMemory => 애플리케이션이 실행될 때 마다 사용자 계정 정보가 바뀔 일이 없음 

이런 방식은 테스트 환경 또는 데모 환경에서만 유용하게 사용

 

SpringSecurity User 

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/User.html

 

SpringSecurity UserDetails 

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/provisioning/UserDetailsManager.html

 

 

3. HTTP 보안 구성 기본 , 커스텀 페이지 지정

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    //HttpSecurity를 통해 HTTP 요청에 대한 보안 설정을 구성
        http
            .csrf().disable()                 
            .formLogin()                      
            .loginPage("/auths/login-form")   
            .loginProcessingUrl("/process_login")    
            .failureUrl("/auths/login-form?error")  
            .and()                                   
            .authorizeHttpRequests()                     
            .anyRequest()                            
            .permitAll();                            

        return http.build();
    }

CSRF(Cross-Site Request Forgery) 공격에 대한 Spring Security에 대한 설정을 비활성화

CSRF Token이 필요해서 비활성화 하지 않으면 403에러 발생

 

loginProcessingUrl("/process_login") 메서드를 통해 로그인 인증 요청을 수행할 요청 URL을 지정

loginProcessingUrl()의 파라미터인 "/process_login"은 미리 작성해둔 html,  form 태그의 action 속성에 지정한 URL과 동일

 

4. request URI 에 접근 권한 부여

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin()
            .loginPage("/auths/login-form")
            .loginProcessingUrl("/process_login")
            .failureUrl("/auths/login-form?error")
            .and()
            .exceptionHandling().accessDeniedPage("/auths/access-denied")   // (1)
            .and()
            .authorizeHttpRequests(authorize -> authorize                  // (2)
                    .antMatchers("/orders/**").hasRole("ADMIN")        // (2-1)
                    .antMatchers("/members/my-page").hasRole("USER")   // (2-2)
                    .antMatchers("⁄**").permitAll()                    // (2-3)
            );
        return http.build();

 

 

 

6. 로그아웃, 관리자 권한 사용자 추가

더보기
@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin()
            .loginPage("/auths/login-form")
            .loginProcessingUrl("/process_login")
            .failureUrl("/auths/login-form?error")
            .and()
            .logout()                        // (1)로그아웃 추가
            .logoutUrl("/logout")            // 
            .logoutSuccessUrl("/")  // 
            .and()
            .exceptionHandling().accessDeniedPage("/auths/access-denied")
            .and()
            .authorizeHttpRequests(authorize -> authorize //roll에 따른 권한 부여
                    .antMatchers("/orders/**").hasRole("ADMIN")
                    .antMatchers("/members/my-page").hasRole("USER")
                    .antMatchers("⁄**").permitAll()
            );
        return http.build();
    }