01. 인가란?
스프링 시큐리티를 활용하여, 가장 먼저 인가 작업을 구현해보고자 한다.
🎈 인가
어느 자원에 대한 요청이 들어왔을 때, 요청한 대상이 해당 자원에 대한 접근 권한을 가졌는지 여부를 처리
인가 처리의 예를 들어보면 아래와 같다.
- 내가 임의의 글을 작성함
- 해당 글의 수정 페이지는 글을 작성한 사람만 접근 가능해야한다.
- 하지만 인가 처리를 하지 않으면, 글을 작성하지 않은 사람 즉 권한이 없는 사람도 수정 페이지에 접근하고 마음대로 글을 바꿀 수 있다.
만약 인가 처리를 해준다면, 이러한 상황을 예방할 수 있다.
그럼 한번 스프링 시큐리티를 사용해 인가 작업을 처리해보자.
02. 스프링 시큐리티로 인가 구현하기
✨ SecurityConfig Class 생성하기
스프링 시큐리티의 인가 설정은 SecurityConfig 클래스 안에서 이루어진다. 먼저 해당 클래스를 만들어주자.
1. 메인 코드 디렉토리 안에 config
디렉토리 생성하기
2. 해당 디렉토리에 SecurityConfig
클래스 생성하기
3. SecurityConfig
클래스에 @Configuration
, @EnableWebSecurity
아노테이션 달아주기
@Configuration
:@Configuration
아노테이션을 달아주면, 해당 클래스 안에서 빈 객체(Bean)를 등록할 수 있고, 해당 빈은 싱글톤이 보장된다.@EnableWebSecurity
:@EnableWebSecurity
가 붙으면 스프링 시큐리티가 활성화된다. 또한 해당 아노테이션이 붙은 클래스 안에서 시큐리티와 관련된 설정을 할 수 있다.
✨ 필터체인 메소드 정의하기
필터체인 메소드를 정의하는 방법은 다음과 같다.
SecurityFilterChain
타입을 반환하는 메소드를 생성한다.- 해당 메소드는
HttpSecurity
객체 변수를 매개변수로 받는다. - 해당 메소드는
@Bean
아노테이션을 붙여서, 메소드에서 반환되는SecurityFilterChain
객체를 빈 객체로 등록한다.
- 해당 메소드는
- 매개 변수로 받은
HttpSecurity
변수를 사용해 인가 처리에 관련된 설정을 진행한다. - 설정을 마친 후
HttpSecurity.build()
메소드를 사용하여, 빌더 패턴으로 생성되는 필터 체인 객체를 반환한다.
메소드의 예시 코드는 아래와 같다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
// 경로별 권한 설정
/**
* requestMatcher: 특정 경로에 대한 요청을 처리
* permitAll: 권한에 상관 없이 모든 요청 허용
* hasRole: 특정 역할이 있으면 접근 허용
* hasAnyRole: 특정 역할(여러개중 어느거나)이 있으면 접근 허용
* anyRequest: 그 외 모든 경로에 대하여 처리
* authenticated: 인증된 사용자만 접근 허용
* !!! 순서 주의. 위에서부터 제한적인 순으로!
*/
http.authorizeHttpRequests((auth)->{
auth
.requestMatchers("/", "/login", "/join", "/joinProc").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated();
});
return http.build();
}
인가 설정 메소드
http.authorizeHttpRequests()
- Http 요청(Request)에 대한 처리를 설정하는 메소드
- 해당 메소드 안에 람다 형식으로 경로별 접근 권한을 설정한다.
- 후술할 경로 매칭 메소드, 권한 처리 메소드를 사용하여 설정
경로 매칭 메소드
requestMatchers(권한 설정할 경로)
- 특정 경로(URI)를 매칭시킨다.
- 이후에 사용되는 권한 설정 함수와 함께 사용하여 경로별로 권한을 처리 할 수 있다.
- 하나의 메소드 안에 여러개의 경로를 매칭시킬 수도 있다.
anyRequest()
- 모든 경로에 대하여 매칭, 뒤에 나올 권한 처리 메소드와 함께 사용
권한 처리 메소드
permitAll()
- 권한에 상관없이 모든 사용자가 해당 경로에 접근 가능하게 설정
authenticated()
- 권한에 상관없이 모든 사용자가 해당 경로에 접근 불가 하게 설정
hasRole(권한)
- 특정 권한을 가진 사용자만 해당 경로에 접근 가능하게 설정
hasAnyRole(권한1, 권한2, ...)
- 여러 권한 중 1개 이상의 권한을 가지면 해당 경로에 접근 가능하게 설정
hasRole()
과 유사함hasAnyRole()
는 여러개의 권한을 동시에 처리 가능
03. 전체 코드
SecurityConfig.java
package com.example.jwt.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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // Spring Security 인가 활성화
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
// 경로별 권한 설정
/**
* requestMatcher: 특정 경로에 대한 요청을 처리
* permitAll: 권한에 상관 없이 모든 요청 허용
* hasRole: 특정 역할이 있으면 접근 허용
* hasAnyRole: 특정 역할(여러개중 어느거나)이 있으면 접근 허용
* anyRequest: 그 외 모든 경로에 대하여 처리
* authenticated: 인증된 사용자만 접근 허용
* !!! 순서 주의. 위에서부터 제한적인 순으로!
*/
http.authorizeHttpRequests((auth)->{
auth
.requestMatchers("/", "/login", "/join", "/joinProc").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated();
});
}
04. 실행 결과
접근이 허용된 페이지 (localhost:8080/join)
정상적으로 페이지에 접근이 가능한 것을 확인할 수 있다.
특정 권한을 요구하는 페이지 (localhost:8080/admin) ("ADMIN" 권한 요구)
해당 페이지에 대한 접근이 거부되며 403 Error
가 발생하는 것을 확인 가능
Reference
'Back End > Spring && Spring Boot' 카테고리의 다른 글
[Spring Security] 회원 가입 로직 (0) | 2024.06.02 |
---|---|
[Spring Boot] Properties 파일 따로 분리하기 (0) | 2024.06.02 |
[Spring Security] Spring Security 개념과 작동 방식 (0) | 2024.06.01 |
[Spring boot] Ambiguous mapping. Cannot map '~' method 에러 (0) | 2024.06.01 |
스프링 부트에서 JDBC Template 사용하기(MySQL) (0) | 2024.06.01 |