728x90
반응형
더보기
package com.example.InstaPrj.config;
import com.example.InstaPrj.security.handler.CustomAccessDeniedHandler;
import com.example.InstaPrj.security.handler.CustomAuthenticationFailureHandler;
import com.example.InstaPrj.security.handler.CustomLoginSuccessHandler;
import com.example.InstaPrj.security.handler.CustomLogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
// 무조건 허용하는 url
private static final String[] AUTH_WHITElIST = {
"/"
};
//
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/* SecurityFilterChain Bean 역할 :
세션 인증 기반 방식으로 대부분의 Spring Security에 대한 설정으로 다룰 수 있다. */
@Bean
protected SecurityFilterChain config(HttpSecurity httpSecurity)
throws Exception {
// csrf 사용안하는 설정
httpSecurity.csrf(httpSecurityCsrfConfigurer -> {
httpSecurityCsrfConfigurer.disable();
});
// authorizeHttpRequests :: 선별적으로 접속을 제한하는 메서드
// 모든 페이지가 인증을 받도록 되어 있는 상태
// httpSecurity.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
httpSecurity.authorizeHttpRequests(
auth -> auth
.requestMatchers(AUTH_WHITElIST).permitAll()
//.requestMatchers("/sample/all").permitAll()
.requestMatchers(new AntPathRequestMatcher("/auth/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/error/**")).permitAll()
.requestMatchers("/sample/admin/**").hasRole("ADMIN")
.requestMatchers("/sample/manager/**").access(
new WebExpressionAuthorizationManager(
"hasRole('ADMIN') or hasRole('MANAGER')")
)
.anyRequest().authenticated());
// formLogin()를 정의해야만 해도 자동생성된 로그인페이지로 이동가능.
httpSecurity.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>() {
@Override
public void customize(FormLoginConfigurer<HttpSecurity> httpSecurityFormLoginConfigurer) {
httpSecurityFormLoginConfigurer
// .loginPage("/sample/login")
// .loginProcessingUrl("/sample/login")
// .defaultSuccessUrl("/")
.successHandler(getAuthenticationSuccessHandler())
.failureHandler(getAuthenticationFailureHandler());
}
});
// logout() 정의 안해도 로그아웃 페이지 사용 가능. 사용자 로그아웃 페이지 지정할 때사용
httpSecurity.logout(new Customizer<LogoutConfigurer<HttpSecurity>>() {
@Override
public void customize(LogoutConfigurer<HttpSecurity> httpSecurityLogoutConfigurer) {
httpSecurityLogoutConfigurer
// logoutUrl() 설정할 경우 html action 주소 또한 같이 적용해야 함.
// logoutUrl()으로 인해 기존 logout 주소 이동은 가능하나 기능은 사용 안됨.
.logoutUrl("/logout")
.logoutSuccessUrl("/") // 로그아웃 후에 돌아갈 페이지 설정
.logoutSuccessHandler(getLogoutSuccessHandler())
.invalidateHttpSession(true); // 서버 세션을 무효화, false도 클라이언트측 무효화
}
});
httpSecurity.oauth2Login(new Customizer<OAuth2LoginConfigurer<HttpSecurity>>() {
@Override
public void customize(OAuth2LoginConfigurer<HttpSecurity> httpSecurityOAuth2LoginConfigurer) {
httpSecurityOAuth2LoginConfigurer.successHandler(
getAuthenticationSuccessHandler()
);
}
});
httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
httpSecurityExceptionHandlingConfigurer.accessDeniedHandler(
getAccessDeniedHandler());
});
httpSecurity.rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
@Override
public void customize(RememberMeConfigurer<HttpSecurity> httpSecurityRememberMeConfigurer) {
// database 아이디를 통하여 로그인하는 경우 사용, 소셜로그인은 사용 불가
httpSecurityRememberMeConfigurer.tokenValiditySeconds(60 * 60 * 24 * 7);
// 익명객체를 활용하여 rememberMe 사용할 때
/*httpSecurityRememberMeConfigurer.rememberMeServices(new RememberMeServices() {
@Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
return null;
}
@Override
public void loginFail(HttpServletRequest request, HttpServletResponse response) {
}
@Override
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
}
});*/
}
});
return httpSecurity.build();
}
// AuthenticationSuccessHandler는 로그인되었을 때 처리하는 객체
@Bean
public AuthenticationSuccessHandler getAuthenticationSuccessHandler() {
return new CustomLoginSuccessHandler();
}
@Bean
public AccessDeniedHandler getAccessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
@Bean
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Bean
public LogoutSuccessHandler getLogoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
// InMemory 방식으로 UserDetailsService(인증 관리 객체) 사용
/*@Bean
public UserDetailsService userDetailsService() {
UserDetails user1 = User.builder()
.username("user1")
.password("$2a$10$XGw3jOo9mQSoij4/so.6H.BtSRWpgPze6ZWMuc7ntyFFWqVNbcmBe")
.roles("USER")
.build();
UserDetails manager = User.builder()
.username("manager")
.password("$2a$10$AEHcuzENZx7OLeA.s8e.t.CvhE/a/GZf.ZKTPEBIKLv8g03zChnD2")
.roles("MANAGER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("1"))
.roles("ADMIN", "MANAGER")
.build();
List<UserDetails> list = new ArrayList<>();
list.add(user1);
list.add(manager);
list.add(admin);
return new InMemoryUserDetailsManager(list);
}*/
}
이 코드는 Spring Boot에서 Spring Security 설정을 관리하는 SecurityConfig
클래스입니다. 이 클래스는 애플리케이션의 보안 설정을 정의하고, 인증 및 권한 부여를 처리하는 중요한 역할을 합니다. 코드를 단계별로 해석해 드리겠습니다.
1. 클래스 선언과 애너테이션
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Configuration
: 이 클래스가 스프링 컨텍스트에서 설정 파일로 인식되도록 합니다.@EnableWebSecurity
: 이 애너테이션은 Spring Security의 웹 보안을 활성화합니다.@EnableMethodSecurity
: 메서드 수준에서 보안을 활성화합니다. 특정 메서드에 권한을 설정하거나 제한을 둘 수 있습니다.
2. 허용된 URL 정의 (화이트리스트)
private static final String[] AUTH_WHITElIST = {
"/"
};
AUTH_WHITElIST
: 인증 없이 접근할 수 있는 URL 목록을 정의합니다. 여기서는 루트 경로("/")만 인증 없이 접근이 가능합니다.
3. 비밀번호 인코더 설정
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
BCryptPasswordEncoder
: 비밀번호를 암호화하는 데 사용되는 인코더입니다.BCrypt
는 단방향 해시 함수로, 비밀번호를 안전하게 암호화하여 데이터베이스에 저장할 수 있게 합니다.
4. SecurityFilterChain 설정
@Bean
protected SecurityFilterChain config(HttpSecurity httpSecurity) throws Exception {
SecurityFilterChain
: 스프링 시큐리티에서 필터 체인을 설정하는 객체입니다. 이 필터 체인을 통해 HTTP 요청이 처리되는 방식을 정의합니다.
5. CSRF 비활성화
httpSecurity.csrf(httpSecurityCsrfConfigurer -> {
httpSecurityCsrfConfigurer.disable();
});
- CSRF(Cross-Site Request Forgery): 사이트 간 요청 위조 방지를 위한 보안 기능입니다. 여기서는 CSRF 보호를 비활성화합니다.
6. HTTP 요청 권한 설정
httpSecurity.authorizeHttpRequests(
auth -> auth
.requestMatchers(AUTH_WHITElIST).permitAll()
.requestMatchers(new AntPathRequestMatcher("/auth/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/error/**")).permitAll()
.requestMatchers("/sample/admin/**").hasRole("ADMIN")
.requestMatchers("/sample/manager/**").access(
new WebExpressionAuthorizationManager(
"hasRole('ADMIN') or hasRole('MANAGER')")
)
.anyRequest().authenticated());
authorizeHttpRequests
: 각 URL 경로에 대한 접근 권한을 설정합니다./auth/**
,/error/**
,/
는 모든 사용자에게 접근 허용 (permitAll()
)./sample/admin/**
는 ADMIN 역할을 가진 사용자만 접근 가능 (hasRole("ADMIN")
)./sample/manager/**
는 ADMIN 또는 MANAGER 역할을 가진 사용자만 접근 가능.- 그 외 모든 요청(
anyRequest()
)은 인증된 사용자만 접근 가능합니다.
7. 폼 로그인 설정
httpSecurity.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>() {
@Override
public void customize(FormLoginConfigurer<HttpSecurity> httpSecurityFormLoginConfigurer) {
httpSecurityFormLoginConfigurer
.successHandler(getAuthenticationSuccessHandler())
.failureHandler(getAuthenticationFailureHandler());
}
});
- 폼 로그인 설정: 사용자가 로그인할 때 사용하는 폼 설정을 정의합니다.
- 성공 시:
getAuthenticationSuccessHandler()
가 호출됩니다. - 실패 시:
getAuthenticationFailureHandler()
가 호출됩니다.
- 성공 시:
8. 로그아웃 설정
httpSecurity.logout(new Customizer<LogoutConfigurer<HttpSecurity>>() {
@Override
public void customize(LogoutConfigurer<HttpSecurity> httpSecurityLogoutConfigurer) {
httpSecurityLogoutConfigurer
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.logoutSuccessHandler(getLogoutSuccessHandler())
.invalidateHttpSession(true);
}
});
- 로그아웃 설정: 로그아웃 시 처리 방식을 정의합니다.
- 로그아웃 URL:
/logout
을 통해 로그아웃. - 성공 후 이동할 URL: 로그아웃 후 루트 경로(
/
)로 리다이렉트. - 세션 무효화: 로그아웃 시 세션을 무효화 (
invalidateHttpSession(true)
).
- 로그아웃 URL:
9. OAuth2 로그인 설정
httpSecurity.oauth2Login(new Customizer<OAuth2LoginConfigurer<HttpSecurity>>() {
@Override
public void customize(OAuth2LoginConfigurer<HttpSecurity> httpSecurityOAuth2LoginConfigurer) {
httpSecurityOAuth2LoginConfigurer.successHandler(
getAuthenticationSuccessHandler()
);
}
});
- OAuth2 로그인 설정: 소셜 로그인을 설정하며, 성공 시
getAuthenticationSuccessHandler()
가 호출됩니다.
10. 예외 처리 핸들러 설정
httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
httpSecurityExceptionHandlingConfigurer.accessDeniedHandler(
getAccessDeniedHandler());
});
- 권한 예외 처리: 사용자가 권한이 없는 페이지에 접근할 때
getAccessDeniedHandler()
가 호출되어 처리됩니다.
11. Remember-Me 기능 설정
httpSecurity.rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
@Override
public void customize(RememberMeConfigurer<HttpSecurity> httpSecurityRememberMeConfigurer) {
httpSecurityRememberMeConfigurer.tokenValiditySeconds(60 * 60 * 24 * 7);
}
});
- Remember-Me 기능: 로그인 세션이 만료된 후에도 사용자가 기억되도록 하는 기능.
- 유효 기간: 7일(60 * 60 * 24 * 7).
12. 핸들러 클래스들
- AuthenticationSuccessHandler: 로그인 성공 시 동작을 정의하는 핸들러입니다.
- CustomLoginSuccessHandler: 로그인 성공 후 처리할 동작을 정의한 사용자 정의 핸들러.
@Bean public AuthenticationSuccessHandler getAuthenticationSuccessHandler() { return new CustomLoginSuccessHandler(); }
- AccessDeniedHandler: 권한이 없을 때 호출되는 핸들러입니다.
@Bean public AccessDeniedHandler getAccessDeniedHandler() { return new CustomAccessDeniedHandler(); }
- AuthenticationFailureHandler: 로그인 실패 시 동작을 정의하는 핸들러입니다.
@Bean public AuthenticationFailureHandler getAuthenticationFailureHandler() { return new CustomAuthenticationFailureHandler(); }
- LogoutSuccessHandler: 로그아웃 성공 시 동작을 정의하는 핸들러입니다.
@Bean public LogoutSuccessHandler getLogoutSuccessHandler() { return new CustomLogoutSuccessHandler(); }
요약
이 코드는 Spring Security의 핵심 설정을 관리하며, 사용자 인증, 권한 부여, 로그인/로그아웃 처리 및 예외 처리 등을 담당합니다. 각 요청에 대해 인증 및 권한을 설정하고, 다양한 핸들러를 통해 성공 및 실패 시 맞춤형 동작을 정의하는 구조입니다.
728x90
반응형
'PROGRAMING📚 > Spring📑' 카테고리의 다른 글
Spring : 구글 로그인 세션 만들기 (1) | 2024.09.25 |
---|---|
Spring Security - USER/MANAGER/ADMIN 에 따른 권한 부여 (0) | 2024.09.25 |
[Spring]::Startbootstrap - Simple Sidebar 사용하기 (0) | 2024.07.11 |
[Spring]::Fragments (0) | 2024.07.11 |
[Spring] 타임리프(Thymeleaf ) (0) | 2024.07.10 |
댓글