Spring Redis Access/Refresh Token 2 - SecurityFilters

손찬호·2024년 6월 28일
0

Spring Boot 3

목록 보기
10/10

의존성 추가

build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

dependencies {
	...
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	...
}

../Entity/Users.java

package com.myweapon.rtc_chatting.Entity;

import java.util.Arrays;
import java.util.List;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Users {
    @jakarta.persistence.Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String roles; // USER,ADMIN

    @Builder
    public Users(String username, String password, String roles) {
        this.username = username;
        this.password = password;
        this.roles = roles;
    }

    public List<String> getRoles() {
        if (roles.length() > 0) {
            return Arrays.asList(roles.split(","));
        }
        return List.of();
    }
}

../Config/CorsConfig.java

Cors정책은 설정해주자.

package com.myweapon.rtc_chatting.Config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/api/**", config);
        return new CorsFilter(source);
    }
}

../Config/SecurityConfig.java

package com.myweapon.rtc_chatting.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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        return http.csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(sessionManagementConfig ->
                        sessionManagementConfig
                                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .formLogin(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(registry ->
                        registry.requestMatchers("api/v1/user/**")
                                .hasAnyRole("USER", "MANAGER", "ADMIN")
                                .requestMatchers("/api/v1/manager/**")
                                .hasAnyRole("USER", "MANAGER", "ADMIN")
                                .requestMatchers("/api/v1/admin/**")
                                .hasAnyRole("MANAGER", "ADMIN")
                                .anyRequest().permitAll())
                .build();
    }
}

filterChain에 준 옵션을 하나씩 살펴보자.

HTTP 보안 설정 정의

@Bean 
public SecurityFilterChain configure(HttpSecurity http) throws Exception

Spring Security의 HTTP 보안 설정을 정의하겠다는 뜻이다.

CRSF 보호

http.csrf(AbstractHttpConfigurer::disable)
CRSF 보호를 비활성화하겠다는 의미로
CSRF(Cross-Site Request Forgery)은
웹 사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행동을 하도록 만드는 공격을 말한다.

비활성화를 해주면 보안이 취약해지는 게 맞다.
하지만 RESTful API같이 클라이언트가 요청마다 토큰을 관리하기 어려운 경우나
서비스가 내부 네트워크에서만 사용되는 특수한 경우에만 CSRF 보호를 비활성화하기도 한다고 한다.

Stateless 세션 정책

.sessionManagement(sessionManagementConfig ->
                        sessionManagementConfig
						.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

stateless란?

state(상태)는 클라이언트 세션 정보를 의미하며
stateless 서버는 요청 간에 클라이언트 세션 정보를 저장하지 않는다는 것을 의미한다.
클라이언트의 각 요청은 이전 요청과 무관한 독립적인 요청으로 처리되고
서버는 클라이언트 세션 상태를 유지하지 않아서 서버의 메모리 사용량을 줄일 수 있다.

session 생성 정책이란?

Spring Security에서 session을 생성할 지 아닐지 정책으로 정한다는 의미이다.

stateless session 생성 정책이란?

세션 관리 정책 중에 하나로 Spring Security가 세션을 생성하거나 사용하지 않는다.
RESTful API와 같이 각 요청이 서로 독립적이어야 하는 경우에 주로 사용한다.
이 정책을 사용하면 모든 요청은 새로운 인증이 필요하고 쿠키 사용이 제한된다.
여기서는 토큰으로 인증을 진행한다.

폼 기반 로그인

formLogin(AbstractHttpConfigurer::disable)
: 폼 기반 로그인을 비활성화

폼 기반 로그인이란?

Spring Security 의존성만 추가하고 애플리케이션을 실행하면
자동으로 Spring Security에서 만든 로그인 페이지로 이동하는데
이걸 비활성화하면 더 이상 나오지 않게 된다.
폼 기반 로그인이 비활성화된다고 해도 최초의 로그인은 수행해야한다.
예를 들어, POST /login 사용해서 ID,password를 보내면 로그인을 수행할 수 있다.
로그인을 수행하면 Token을 받게되고 이후에 모든 요청에 token을 담아 ID,password를
추가로 보내지 않아도 된다.

HTTP Basic 인증

httpBasic(AbstractHttpConfigurer::disable)
:HTTP Basic 인증을 비활성화

HTTP Basic 인증이란?

stateless 방식으로 클라이언트는 매 요청마다 인증 정보를 전송해야하는 방식이다.
반면 HTTP Basic 인증을 비활성화하면 클라이언트는 사용자 이름과 비밀번호를 제공하지
않아도 요청을 보낼 수 있게 된다. 토큰만 들고 있으면 요청을 보낼 수 있도록 하기위해
비활성화를 했다.

HTTP 요청 접근 제어 규칙

.authorizeHttpRequests(registry ->
                        registry.requestMatchers("api/v1/user/**")
                                .hasAnyRole("USER", "MANAGER", "ADMIN")
                                .requestMatchers("/api/v1/manager/**")
                                .hasAnyRole("USER", "MANAGER", "ADMIN")
                                .requestMatchers("/api/v1/admin/**")
                                .hasAnyRole("MANAGER", "ADMIN")
                                .anyRequest().permitAll())
  • registry.requestMatchers("api/v1/user/**").hasAnyRole("USER", "MANAGER", "ADMIN"):
    /api/v1/manager/** 경로의 모든 요청에 대해
    “USER”, “MANAGER”, “ADMIN” 역할 중 하나 이상을 가진 사용자만 접근할 수 있도록 설정한다.
  • registry.requestMatchers("/api/v1/admin/**").hasAnyRole("MANAGER", "ADMIN"):
    /api/v1/admin/** 경로로 시작하는 모든 요청에 대해 “MANAGER” 또는 “ADMIN” 역할을 가진 사용자만 접근할 수 있도록 설정한다.
    "USER"역할의 사용자는 접근할 수 없도록 제한을 걸기위해 사용한다.
  • anyRequest().permitAll():
    위에서 명시적으로 설정되지 않은 모든 다른 요청은 모든 사용자가 접근할 수 있도록 설정한다.
    어떤 역할을 가지지 않은 비회원 사용자도 요청을 할 수 있다.

SecurityFilterChain 객체 생성

build()
지금까지 만든 필터를 하나의 SecurityFilterChain 객체로 합쳐서 생성한다.

profile
매일 1%씩 성장하려는 주니어 개발자입니다.

0개의 댓글