👩💻 Spring Security - 스프링부트 시큐리티
📌 스프링부트 시큐리티 설정
✏️ Spring Security 적용하기
스프링 시큐리티를 적용하기위해, 아래와 의존성을 추가해주자!
의존성을 추가해주면 모든 경로에 대해서 로그인 화면이 보이게 된다. 즉, 현재 프로젝트는 모든 페이지에 대해서 로그인을 통해 접근할 수 있게 된다.
Gradle
implementation 'org.springframework.boot:spring-boot-starter-security'
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
✏️ SecurityConfig - 시큐리티 설정하기
Spring Security를 사용하여 웹 애플리케이션의 보안을 설정한다.
주로 HTTP 요청에 대한 인증 및 권한 부여 규칙을 설정하고, 특정 경로에 대한 접근 권한을 제어하는 역할을 한다.
이 클래스에서 정의한 내용은 "Spring Security 필터 체인"에 해당하며, SecurityFilterChain은 요청이 들어올 때마다 해당 요청을
처리할 필터들의 목록을 정의하며, 이 필터들이 요청을 가로채어 인증 및 권한 부여, CSRF 보호 등 다양한 보안 작업을 수행한다.

@Configuration & @EnableWebSecurity

- @Configuration
:이 클래스가 Spring 설정 클래스임을 나타낸다. Spring에서 이 클래스의 메서드들이 Bean(빈)으로 등록되어 다른 구성 요소에서 사용할 수 있도록 한다. - @EnableWebSecurity
:Spring Security를 활성화하는 애노테이션이다. 이를 통해 Spring Security의 기본 필터 체인이 활성화되고, 이 클래스의 설정이 Spring Security 설정에 반영된다.

filterChain 메서드
:Spring Security의 각종 설정은 HttpSecurity로 대부분 이루어진다
ex) URL 접근 권한 설정
- 인증 전체 흐름에 필요한 Login & Logout 페이지 인증완료 후, 페이지 인증 실패 시 이동 페이지 등등 설정
- 인증로직을 커스텀하기 위한 커스텀 필터 설정
- 기타 csrf, 강제 https 호출 등등 거의 모든 설정
리소스 권한 설정하기

이 메서드는 SecurityFilterChain을 구성하고 반환한다. "SecurityFilterChain"은 애플리케이션에 적용되는 보안 필터의 체인을 의미 !
- http.csrf(AbstractHttpConfigurer::disable)
:CSRF(Cross-Site Request Forgery) 보호 비활성화(disable)를 말한다. CSRF 공격을 방지하는 보호 기능을 비활성화한다는 뜻으로, 일반적으로 RESTful API나 CSRF 보호가 불필요한 상황에서 비활성화 한다. (연습과정이라 비활성화 했습니다!!!!!)
💡여기서 CSRF란?
CSRF란 사이트간 요청 위조를 뜻합니다! CSRF는 웹 보안 취약점의 일종이며, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정 삭제 등록 등..)을 특정 웹사이트에 요청하게 하는 공격을 말합니다!
- .authorizeHttpRequests(authorize -> authorize...)
:HTTP 요청에 대한 접근 권한을 설정한다.
- requestMatchers("/user/**").authenticated()
:"/user/**" 경로로 들어오는 요청은 인증된 사용자만 접근할 수 있도록 설정한다. - requestMatchers("/admin/**").hasAnyRole("MANAGER", "ADMIN")
:"/admin/**" 경로는 MANAGER 또는 ADMIN 역할을 가진 사용자만 접근할 수 있도록 설정한다. - anyRequest().permitAll()
:그 외의 모든 요청은 인증 없이 접근을 허용합니다.
- requestMatchers("/user/**").authenticated()
로그인 처리 설정
로그인 처리 설정을 하지 않으면 허용되지 않는 리소스에 대해서 403에러가 발생하기 때문에 로그인 처리 설정을 해주어야한다.

- loginPage("/login")
:로그인 페이지 경로를 '/login'으로 지정한다. 인증이 필요한 상황에서 로그인 페이지로 리다이렉트 된다. - permitAll()
:로그인 페이지는 인증 없이 누구나 접근할 수 있도록 설정한다. - http.build()
:이 설정을 바탕으로 "SecurityFilterChain" 객체를 생성하고 반환한다.
📌 시큐리티 회원가입
✏️ Spring Security를 적용하여 회원가입 기능을 구현해보자.
사용자가 회원가입을 진행하였을 때, 스프링 시큐리티를 적용하여 사용자의 정보를 DB에 저장해보자~!
User 앤티티와 UserRepository 생성


💡사실 @Repository를 생략해도 된다.
UserRepository는 JpaRepository를 상속받았기 때문에 @Repository라는 애노테이션이 없어도 IoC가 된다.
"JpaRepository"는 스프링 데이터 JPA가 자동으로 리포지토리 빈을 생성하고 관리하도록 하기 때문이다!
스프링 프레임워크에서는 특정 인터페이스를 구현하는 클래스를 자동으로 스캔하고, 빈으로 등록해주는 메커니즘이 존재한다.
User 의 비밀번호 암호화 진행
회원가입 폼을 입력하면 사용자의 정보를 user 객체에 바인딩하여 user의 권한을 지정해준 뒤, 리포지토리에 저장하도록 해주었다.
이렇게 코드를 작성할 경우, 회원가입은 잘 되지만 패스워드가 암호화 되어있지않기 때문에 비밀번호가 그대로 노출되어 Spring의 시큐리티를 이용하여 로그인할 수 없다.



PasswordEncoder Interface의 구현체인 BCryptPasswordEncoder를 활용하자
Spring Security에서는 비밀번호 암호화(Encoding)을 진행하기 위해 PasswordEncoder 인터페이스를 제공하며, 그 중
PasswordEncoder의 구현체 중 하나로, BCrypytPasswordEncoder를 제공한다.

SecurityConfig에 BCryptPasswordEncoder객체를 생성하여 반환해주는 encodePwd라는 메서드를 생성하여 스프링 빈을 생성


💡왜 SecurityConfig가 아닌 BCryptPasswordEncoder를 의존성 주입 받았을까?
"단일 책임 원칙(Single Responsibility Principle)"
- SecurityConfig의 역할: 애플리케이션의 보안 설정을 담당
- BCryptPasswordEncoder의 역할: 비밀번호를 해싱하는 구체적인 작업을 수행
두 클래스는 서로 다른 책임을 가지고있다. 의존성을 주입받을 때 불필요한 의존성은 회피하는것이 좋다.
만약 "IndexController"가 "SecurityConfig"를 의존성 주입받았다면, 보안설정에 대한 정보까지 알게 된다.
하지만 "IndexContorller"는 보안 설정 자체에 관심이 있을 필요가 없고, 오직 비밀번호 암호화 기능만 활용하면 된다.
따라서 불필요한 의존성을 줄이고, 필요한 것만 주입받는 것이 더 적절하다.

PasswordEncoder도 만들었으니 컨트롤러를 수정해주자.
파라미터로 받아온 사용자의 정보에서 비밀번호를 가져와 bCryptPasswordEncoder를 통해 encode해주어 저장했다.
이후 userRepository를 통해 저장한 뒤, 회원가입 폼을 이용하여 다시 회원가입을 진행해보았다.

DB에 password가 암호화되어 잘 저장된 것을 볼 수 있었다~!
📌 스프링부트 시큐리티 로그인
✏️ Spring Security 로그인을 적용해보자.
위와같이 스프링 시큐리티를 사용하여 회원가입을 진행하고 DB에 회원 비밀번호를 암호화하여 저장하는 작업까지 진행했다면, 이제 시큐리티를 활용한 로그인 기능을 구현해보자!
'loginProcessingUrl'과 로그인 처리
'loginProcessingUrl'은 로그인 폼에서 제출된 로그인 요청을 "특정 URL('/login')"으로 매핑한다.
(요청이 들어오면, 스프링 시큐리티는 "UsernamePasswordAuthenticationFilter"를 사용하여 로그인 요청을 처리한다.)

UserDetailsService 와 loadUserByUsername 호출
"/login"요청이 들어오면 자동으로 UserDetailsService 타입으로 IoC 되어있는 loadUserByUsername이 호출된다.
이 메서드는 사용자의 자격 증명(예: 사용자 이름)으로부터 "UserDetails" 객체를 로드하여 반환한다.
스프링 시큐리티의 인증 프로세스에서 중요한 역할을 하며, "UserDetails"객체를 반환해야 한다.

세션 영역의 오브젝트 타입: Authentication & UserDetails
로그인 과정이 성공하면, 스프링 시큐리티는 "Authentication"객체를 생성하여 보안 컨텍스트(Security Context)에 Authentication객체를 저장한다. 이때, Authentication 객체는 "UserDetails"를 포함하고 있으며, 로그인한 사용자의 권한과 정보를 담고 있다.



UserDetailsService 객체: 로그인 과정에서 사용자 정보를 로드하는 서비스이다. 주어진 사용자 이름으로 "UserDetails" 객체를 반환한다.
Authentication 객체: 인증된 사용자와 관련된 정보를 담고 있으며, 보안 컨텍스트에 저장된다.
UserDetails 객체: "Authentication"객체 내부에 포함되어 사용자의 상세 정보를 제공한다.
정리
- UserDetailsService: 사용자 이름을 기반으로 "userDetails"객체를 로드하여 반환하는 역할을 한다. 로그인 과정에서 호출된다.
- Authentication: 로그인 성공 후, 사용자 인증 정보를 담고 있는 객체. 보안 컨텍스트에 저장되어 사용자의 인증 상태를 유지한다.
- UserDetails: Authentication 객체 내부에 포함되어, 인증된 사용자의 정보를 제공하는 객체이다.
📌 시큐리티 권한
✏️ 권한에 따라 URL 접근 제어를 설정하는 방법!
아래와같이 Admin, Manager, User라는 아이디를 각각 만든 뒤, 그에 맞는 권한(ROLE)을 부여해두었다.



URL 기반 접근 제어
URL 기반 접근 제어는 주로 웹 애플리케이션의 특정 URL 경로에 대해 접근 권한을 제어하는 데 사용된다.
이 방식은 스프링 시큐리티의 "HttpSercurity" 설정을 통해서 적용된다.

@Secured, @PreAuthroize를 활용한 메소드 수준의 보안
메소드 수준의 보안은 특정 메소드에 대해 세밀한 접근 제어를 적용할 때 사용하면 된다. @Secured, @PreAuthorize, @PostAuthorize 애노테이션을 통해 구현 된다.

@Secured & @PreAuthorize 등의 애노테이션을 사용해주기 위해 우선 Security 설정 클래스에 @EnableGlobalMethodSecurity를 추가해야한다.
- securedEnabled = true
:@Secured 애노테이션 활성화 - prePostEnabled = true
:@preAuthorize & @postAuthorize 애노테이션 활성화
메소드 수준의 보안 적용해보기
Security 설정 클래스에 @EnableGlobalMethodSecurity (securedEnable = true, prePostEnabled = true) 애노테이션을 추가한 뒤, 아래와 같이 Contorller에서 두개의 메서드를 생성해주었다.
1. info
: @Secured 애노테이션을 활용하여 'ADMIN' 권한 소유자만 접근할 수 있는 Url
2. data
: @PreAuthorize 애노테이션을 활용하여 'ADMIN' 권한 소유자만 접근할 수 있는 Url

로그인하지 않고 "/info" 혹은 "/data" URL에 접근 시
자동으로 로그인 페이지로 이동한다.


User 혹은 Manager로 /info, /data URL에 접근할 시,
User 권한을 가진 사용자와 Manager 권한을 가진 사용자 모두 Admin 권한이 주어진 사용자만 접근가능한 info, data URL에 접근하자 403 상태코드가 또는 것을 확인할 수 있었다. (status=403. 접근이 거부되었습니다.)




Admi으로 /info, /data URL에 접근할 시,
Admin 권한을 가지고있는 사용자 아이디로 접속하니 info와 data URL에 모두 정상적으로 접근할 수 있었다~!



정리
URL 기반 접근 제어
:설정이 간단하고 직관적이며, 보안 설정을 중앙에서 관리하는 데 유리하다.
활용
- 단순한 보안 요구 사항이 있는 경우
- URL 패턴별로 명확한 권한을 설정하고 하는 경우
메소드 수준 접근 제어
: 비즈니스 로직에 따라 세부적인 권한 제어가 필요할 때 적합하다. 권한 검사를 메소드 수준에서 세밀하게 조정할 수 있어, 복잡한 보안 요구 사항을 처리하는 데 유리하다.
활용
- 새부적인 권한 제어가 필요한 경우
- 특정 메소드에 대한 권한을 명확히 구분해야 하는 경우
강의
[지금 무료] 스프링부트 시큐리티 & JWT 강의 강의 | 최주호 - 인프런
최주호 | 스프링부트 시큐리티에 대한 개념이 잡힙니다., 스프링부트 시큐리티,제가 공부했던 걸 쉽게 설명드릴게요 🙂 스프링부트 시큐리티 github https://github.com/codingspecialist/-Springboot-Security-OAu
www.inflearn.com
참고 블로그
https://velog.io/@wooyong99/Spring-Security
Spring Security- SecurityFilterChain사용
스프링부트 3.0부터 스프링 시큐리티 6.0.0이상의 버전이 적용되었습니다. 2.7.3이후로 시큐리티 설정쪽에 drprecated 되는게 추가되었고 3.0부터는 아예 삭제된 설정방식들이 있습니다. GradleMaven의존
velog.io
Spring Security를 이용한 비밀번호 암호화 로직 구현 과정 기록
오늘은 회원 관리 시스템에서 평문(plain text)으로 암호를 저장하는 것은 보안상 굉장히 위험하기 때문에, 이를 Spring Security를 이용해 암호화(Encryption)하는 과정을 진행하고, 기록하려 합니다. Sprin
kkkdh.tistory.com
'Spring' 카테고리의 다른 글
| [ Spring ] 동시성을 잠금으로 안전하게 처리해보자 (0) | 2025.09.19 |
|---|---|
| [SQL]Error: 1406-22001: Data too long for column '?' at row 1 (0) | 2024.10.01 |
| [Spring] 컨트롤러 예외처리(Exception Handling) (0) | 2024.07.21 |
| [Mockito] Mockito란 무엇일까? (0) | 2024.07.04 |
| [Spring] 연관관계 매핑 (0) | 2024.06.30 |