
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package com.takensoft.common.config;
import com.takensoft.cms.accesCtrl.service.AccesCtrlService;
import com.takensoft.cms.cntxtPth.service.CntxtPthService;
import com.takensoft.cms.loginPolicy.service.LoginModeService;
import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
import com.takensoft.cms.mber.service.LgnHstryService;
import com.takensoft.cms.token.service.RefreshTokenService;
import com.takensoft.common.filter.*;
import com.takensoft.common.util.HttpRequestUtil;
import com.takensoft.common.exception.CustomAccessDenieHandler;
import com.takensoft.common.exception.CustomAuthenticationEntryPoint;
import com.takensoft.common.util.JWTUtil;
import com.takensoft.common.util.SessionUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Collections;
/**
* @author takensoft
* @since 2025.01.22
* @modification
* since | author | description
* 2025.01.22 | takensoft | 최초 등록
*
* Spring Security 설정을 위한 Config
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// AuthenticationManager가 인자로 받을 AuthenticationConfiguration 객체 생성자 주입
private final AuthenticationConfiguration authenticationConfiguration;
private final JWTUtil jwtUtil;
private final RefreshTokenService refreshTokenService;
private final LgnHstryService lgnHstryService;
private final CntxtPthService cntxtPthService;
private final AccesCtrlService accesCtrlService;
private final CustomAuthenticationEntryPoint authenticationEntryPoint;
private final CustomAccessDenieHandler accessDenieHandler;
private final HttpRequestUtil httpRequestUtil;
private final AppConfig appConfig;
private final LoginModeService loginModeService;
private final LoginPolicyService loginPolicyService;
private final SessionUtil sessionUtil;
private static String FRONT_URL; // 프론트 접근 허용 URL
private static long JWT_ACCESSTIME; // access 토큰 유지 시간
private static long JWT_REFRESHTIME; // refresh 토큰 유지 시간
private static int COOKIE_TIME; // 쿠키 유지 시간
private final RedisTemplate<String, String> redisTemplate;
/**
* @param authenticationConfiguration - 인증 구성 객체
* @param jwtUtil - JWT 유틸리티 객체
* @param authenticationEntryPoint - 인증 실패 시 처리 엔트리 포인트
* @param accessDenieHandler - 접근 거부 처리 핸들러
* @param fUrl - 프론트엔드 URL (application.yml에서 값을 읽어 옴)
* @param aTime - JWT 접근 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
* @param rTime - JWT 리프레시 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
* @param ctime - 쿠키 유효 시간 (application.yml에서 값을 읽어 옴)
* @param redisTemplate
*
*/
public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, CntxtPthService cntxtPthService, AccesCtrlService accesCtrlService, AppConfig appConfig,
LgnHstryService lgnHstryService, CustomAuthenticationEntryPoint authenticationEntryPoint, CustomAccessDenieHandler accessDenieHandler, HttpRequestUtil httpRequestUtil,
LoginModeService loginModeService, LoginPolicyService loginPolicyService, SessionUtil sessionUtil, @Value("${front.url}") String fUrl, @Value("${jwt.accessTime}") long aTime, @Value("${jwt.refreshTime}") long rTime, @Value("${cookie.time}") int ctime, RedisTemplate<String, String> redisTemplate) {
this.authenticationConfiguration = authenticationConfiguration;
this.refreshTokenService = refreshTokenService;
this.lgnHstryService = lgnHstryService;
this.cntxtPthService = cntxtPthService;
this.accesCtrlService = accesCtrlService;
this.authenticationEntryPoint = authenticationEntryPoint;
this.accessDenieHandler = accessDenieHandler;
this.jwtUtil = jwtUtil;
this.httpRequestUtil = httpRequestUtil;
this.appConfig = appConfig;
this.loginModeService = loginModeService;
this.loginPolicyService = loginPolicyService;
this.sessionUtil = sessionUtil;
this.FRONT_URL = fUrl;
this.JWT_ACCESSTIME = aTime;
this.JWT_REFRESHTIME = rTime;
this.COOKIE_TIME = ctime;
this.redisTemplate = redisTemplate;
}
/**
* @param configuration - 인증 구성 객체
* @return AuthenticationManager 객체
* @throws Exception - 인증 관리자 초기화 실패 시
*
* AuthenticationManager Bean 등록
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
/**
* @return BCryptPasswordEncoder 객체
*
* 비밀번호 해시 암호화를 위한 Bean 등록
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* @param http - HTTP 보안 설정 객체
* @return SecurityFilterChain 객체
* @throws Exception - 보안 필터 체인 초기화 실패 시
*
* Spring Security 필터 체인 설정
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors((cors) -> cors
.configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList(FRONT_URL)); // 허용할 프론트 포트 포함 경로 입력
configuration.setAllowedMethods(Collections.singletonList("*")); // 허용할 메소드(GET, POST, PUT 등)
configuration.setAllowedHeaders(Collections.singletonList("*")); // 허용할 헤드
configuration.setAllowCredentials(true); // 프론트에서 credentials 설정하면 true
configuration.setMaxAge(3600L); // 허용을 물고 있을 시간
configuration.setExposedHeaders(Collections.singletonList("Authorization")); // 서버에서 JWT를 Authorization에 담아 보내기 위해 허용을 함
return configuration;
}
})
);
// csrf disable
http.csrf((auth) -> auth.disable());
// formLogin disable
http.formLogin((auth) -> auth.disable());
// http basic 인증 방식 disable
http.httpBasic((auth) -> auth.disable());
// 세션 설정
http.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
// Context Path 검증 필터
http.addFilterBefore(new ContextPathFilter(cntxtPthService), SecurityContextPersistenceFilter.class);
http.exceptionHandling((exception) -> exception
.authenticationEntryPoint(authenticationEntryPoint) // 접근 권한이 없는 경우에 호출
.accessDeniedHandler(accessDenieHandler) // 인증되지 않은 상태로 접근 했을 때 호출
);
http.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/mbr/**", "/company/**", "/refresh/**", "/sys/**").permitAll() // 회원관련, 시스템 제공 관련, 기업용페이지는 누구나 접근 가능
.requestMatchers("/admin/**").hasRole("ADMIN") // 관리자 페이지는 ADMIN 권한을 가진 사용자만 접근 가능
.requestMatchers("/editFileUpload/**", "/fileUpload/**").permitAll() // 에디터 파일 업로드
.anyRequest().authenticated() // 그 외에는 로그인한 사용자만 접근 가능
// .anyRequest().permitAll() // 모든 사용자 접근 가능
);
http.addFilterBefore(new JWTFilter(jwtUtil, appConfig, loginModeService, loginPolicyService, redisTemplate), LoginFilter.class);
http.addFilterBefore(new AccesFilter(accesCtrlService, httpRequestUtil, appConfig), JWTFilter.class); // 아이피 검증
http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, httpRequestUtil,
loginModeService, loginPolicyService, sessionUtil, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME, redisTemplate), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
return http.build();
}
}