Spring Security란?
Spring Security는 Java 기반 애플리케이션에서 보안을 쉽게 구현하고 관리할 수 있도록 도와줍니다. 개발자는 애플리케이션의 보안에 더 많은 신경을 쓰지 않고 안전하게 애플리케이션을 개발할 수 있습니다.
Spring Security의 기본적인 필터 실행 순서
- SecurityContextPersistenceFilter: 현재 사용자의 보안 컨텍스트를 로드 및 저장하는 필터입니다. 세션 또는 SecurityContextHolder를 통해 현재 사용자의 보안 컨텍스트를 관리합니다.
- ConcurrentSessionFilter: 동시 세션 제어를 수행하는 필터입니다. 세션 고유 키를 사용하여 여러 동시 로그인을 제한하거나 처리합니다.
- LogoutFilter: 로그아웃 처리를 위한 필터입니다. 사용자의 로그아웃 요청을 처리하고 세션을 종료합니다.
- UsernamePasswordAuthenticationFilter: 폼 기반 로그인을 처리하는 필터입니다. 사용자가 아이디와 비밀번호로 로그인할 때 작동합니다.
- BasicAuthenticationFilter: HTTP 기본 인증을 처리하는 필터입니다.
- RequestCacheAwareFilter: 이전 요청의 캐시를 관리하고 요청이 캐시되었는지 확인합니다.
- SecurityContextHolderAwareRequestFilter: 보안 컨텍스트를 사용하여 HttpServletRequest 및 HttpServletResponse를 래핑합니다.
- AnonymousAuthenticationFilter: 사용자가 인증되지 않았을 때 익명 사용자로 설정하는 필터입니다.
- SessionManagementFilter: 세션 관리를 처리하는 필터로 세션 무효화 및 세션 고정 공격 방어 등을 다룹니다.
- ExceptionTranslationFilter: 예외 처리 및 보안 예외를 처리하는 필터입니다.
- FilterSecurityInterceptor: 요청에 대한 보안 검사 및 인가(Authorization)를 처리하는 필터로, 실제 권한 부여 작업을 수행합니다.
- 사용자 정의 필터: 프로젝트에서 직접 추가한 사용자 정의 보안 필터들이 여기에 위치할 수 있습니다. 이 필터들은 addFilterBefore() 또는 addFilterAfter() 메서드를 사용하여 추가됩니다.
- LogoutFilter: 로그아웃 처리를 위한 필터로, 로그아웃 요청을 처리하고 세션을 종료합니다. 이 필터는 기본적으로 두 번 등록되며, 로그아웃 처리와 로그아웃 URL 접근을 다룹니다.
- SecurityContextLogoutHandler: 로그아웃 처리를 위한 핸들러입니다. 사용자의 로그아웃 요청을 처리하고 세션을 종료합니다.
- RequestCacheAwareFilter: 이전 요청의 캐시를 관리하고 요청이 캐시되었는지 확인합니다.
- SecurityContextHolderAwareRequestFilter: 보안 컨텍스트를 사용하여 HttpServletRequest 및 HttpServletResponse를 래핑합니다.
- AnonymousAuthenticationFilter: 사용자가 인증되지 않았을 때 익명 사용자로 설정하는 필터입니다.
- SessionManagementFilter: 세션 관리를 처리하는 필터로 세션 무효화 및 세션 고정 공격 방어 등을 다룹니다.
- ExceptionTranslationFilter: 예외 처리 및 보안 예외를 처리하는 필터입니다.
- FilterSecurityInterceptor: 요청에 대한 보안 검사 및 인가(Authorization)를 처리하는 필터로, 실제 권한 부여 작업을 수행합니다.
Spring Security 흐름 사진
저의 애플리케이션의 권한은 일반 회원과 관리자로 나뉘어져있고 일반 회원은 관리자페이지를 제외하고 모든 페이지에 접근 할 수 있습니다. 따라서 관리자 페이지만 권한을 확인합니다.
- 프로젝트 구조
- pom.xml
<!-- Spring Security -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
- WebConfig
@Configuration
@ComponentScan(basePackages = {"com.jam"})
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// Spring Security 설정 파일을 추가합니다.
return new Class[]{RootConfig.class, SecurityConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ServletConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
}
- web.xml 을 이용한다면
web.xml
package com.jam.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer{
// 스프링 시큐리티가 제공하는 필터들을 사용할 수 있도록 활성화 해준다.
}
- SecurityConfig (jwt 빼기)
package com.jam.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.jam.security.CustomLoginSuccessHandler;
import com.jam.security.CustomUserDetailsService;
import com.jam.security.JwtAuthenticationFilter;
import com.jam.security.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@Configuration
@EnableWebSecurity(debug = true)
//@RequiredArgsConstructor
@Log4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Setter
private DataSource dataSource;
@Bean
public AuthenticationSuccessHandler loginSuccessHandler() {
return new CustomLoginSuccessHandler();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService customUserService() {
return new CustomUserDetailsService();
}
private JwtTokenProvider jwtTokenProvider;
public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
//.antMatchers("/admin/admin").hasRole("ROLE_ADMIN")
.antMatchers("/*").permitAll()
.and()
.formLogin().loginPage("/member/login") // 커스텀 로그인 페이지 URL
.permitAll() // 로그인 페이지는 모든 사용자에게 허용
.loginProcessingUrl("/member/login")
.successHandler(loginSuccessHandler())
.usernameParameter("user_id")
.passwordParameter("user_pw")
//.failureUrl("/member/login?error")
/*로그인 실패하면 기본적으로 /login?error로 리디렉션*/
.and()
.logout() // 로그아웃 설정
.logoutUrl("/member/logout") // 로그아웃 URL
//.invalidateHttpSession(true)
//.deleteCookies("remember-me","JSESSTION_ID")
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class)
.csrf().disable();
}
/*customUserService 인증 되면 -> 스프링 시큐리티가 Authentication 객체를 자동으로 생성 -> */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(customUserService()).passwordEncoder(passwordEncoder());
}
}
'프로젝트 > JAM' 카테고리의 다른 글
---- (0) | 2024.02.05 |
---|---|
-- (0) | 2023.12.04 |
[SpringMVC] Spring Security + JWT토큰 (1) | 2023.10.03 |
[Spring] 네이버 소셜 로그인 구현 REST API (0) | 2023.08.24 |
[Spring] 카카오 소셜 로그인 구현 REST API (0) | 2023.08.21 |