This commit is contained in:
mindol1004
2024-08-26 18:48:20 +09:00
parent ade2aa0733
commit f1ddadfb9b
28 changed files with 214 additions and 138 deletions

View File

@@ -0,0 +1,63 @@
package com.spring.common.util;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ApplicationUtil {
public static ServletRequestAttributes getServletRequestAttributes(){
return (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
}
//Request 객체 얻기
public static HttpServletRequest getRequest(){
return getServletRequestAttributes().getRequest();
}
//Set Request Attribute
public static void setRequestAttributes(String key, Object obj){
getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_REQUEST);
}
//Get Request Attribute
public static Object getRequestAttributes(String key){
return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_REQUEST);
}
//Session 객체 얻기
public static HttpSession getSession(){
return getRequest().getSession();
}
//Set Session Attributes
public static void setSessionAttributes(String key, Object obj){
getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_SESSION);
}
//Get Session Attributes
public static Object getSessionAttributes(String key){
return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_SESSION);
}
//HttpServletResponse 객체 얻기
public static HttpServletResponse getResponse(){
return getServletRequestAttributes().getResponse();
}
//beanName을 통해서 Bean을 얻을 수 있다.
public static Object getBean(String beanName){
var context = ContextLoader.getCurrentWebApplicationContext();
if (context == null) {
throw new IllegalStateException("WebApplicationContext를 찾을 수 없습니다.");
}
return context.getBean(beanName);
}
}

View File

@@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_JOB_EXECUTION") // @Table(name = "BATCH_JOB_EXECUTION")
@Getter @Getter
public class BatchJobExecution { public class BatchJobExecution {

View File

@@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_JOB_EXECUTION_CONTEXT") // @Table(name = "BATCH_JOB_EXECUTION_CONTEXT")
@Getter @Getter
public class BatchJobExecutionContext { public class BatchJobExecutionContext {

View File

@@ -13,8 +13,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_JOB_EXECUTION_PARAMS") // @Table(name = "BATCH_JOB_EXECUTION_PARAMS")
@Getter @Getter
public class BatchJobExecutionParams { public class BatchJobExecutionParams {

View File

@@ -9,9 +9,9 @@ import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint; import jakarta.persistence.UniqueConstraint;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_JOB_INSTANCE", // @Table(name = "BATCH_JOB_INSTANCE",
uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"})) // uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"}))
@Getter @Getter
public class BatchJobInstance { public class BatchJobInstance {

View File

@@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_STEP_EXECUTION") // @Table(name = "BATCH_STEP_EXECUTION")
@Getter @Getter
public class BatchStepExecution { public class BatchStepExecution {

View File

@@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "BATCH_STEP_EXECUTION_CONTEXT") // @Table(name = "BATCH_STEP_EXECUTION_CONTEXT")
@Getter @Getter
public class BatchStepExecutionContext { public class BatchStepExecutionContext {

View File

@@ -0,0 +1,51 @@
package com.spring.domain.email.batch;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import com.spring.infra.quartz.QuartzJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
@RequiredArgsConstructor
public class EmailSendBatch {
private final JobRepository jobRepository;
private final PlatformTransactionManager transactionManager;
@QuartzJob(name = "emailSendJob", cronExpression = "*/3 * * * * ?")
@Bean(name = "emailSendJob")
Job emailSendJob(Step emailSendStep) {
log.info(">>> emailSendJob");
return new JobBuilder("emailSendJob", jobRepository)
.start(emailSendStep)
.build();
}
@Bean("emailSendStep")
Step emailSendStep(Tasklet emailSendTasklet) {
log.info(">>> emailSendStep");
return new StepBuilder("emailSendStep", jobRepository)
.tasklet(emailSendTasklet, transactionManager).build();
}
@Bean
Tasklet emailSendTasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> emailSendTasklet");
return RepeatStatus.FINISHED;
});
}
}

View File

@@ -12,8 +12,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_BLOB_TRIGGERS") // @Table(name = "QRTZ_BLOB_TRIGGERS")
@Getter @Getter
public class QrtzBlobTriggers { public class QrtzBlobTriggers {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_CALENDARS") // @Table(name = "QRTZ_CALENDARS")
@Getter @Getter
public class QrtzCalendars { public class QrtzCalendars {

View File

@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_CRON_TRIGGERS") // @Table(name = "QRTZ_CRON_TRIGGERS")
@Getter @Getter
public class QrtzCronTriggers { public class QrtzCronTriggers {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_FIRED_TRIGGERS") // @Table(name = "QRTZ_FIRED_TRIGGERS")
@Getter @Getter
public class QrtzFiredTriggers { public class QrtzFiredTriggers {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_JOB_DETAILS") // @Table(name = "QRTZ_JOB_DETAILS")
@Getter @Getter
public class QrtzJobDetails { public class QrtzJobDetails {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_LOCKS") // @Table(name = "QRTZ_LOCKS")
@Getter @Getter
public class QrtzLocks { public class QrtzLocks {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_PAUSED_TRIGGER_GRPS") // @Table(name = "QRTZ_PAUSED_TRIGGER_GRPS")
@Getter @Getter
public class QrtzPausedTriggerGrps { public class QrtzPausedTriggerGrps {

View File

@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_SCHEDULER_STATE") // @Table(name = "QRTZ_SCHEDULER_STATE")
@Getter @Getter
public class QrtzSchedulerState { public class QrtzSchedulerState {

View File

@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_SIMPLE_TRIGGERS") // @Table(name = "QRTZ_SIMPLE_TRIGGERS")
@Getter @Getter
public class QrtzSimpleTriggers { public class QrtzSimpleTriggers {

View File

@@ -15,8 +15,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_SIMPROP_TRIGGERS") // @Table(name = "QRTZ_SIMPROP_TRIGGERS")
@Getter @Getter
public class QrtzSimpropTriggers { public class QrtzSimpropTriggers {

View File

@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@Entity // @Entity
@Table(name = "QRTZ_TRIGGERS") // @Table(name = "QRTZ_TRIGGERS")
@Getter @Getter
public class QrtzTriggers { public class QrtzTriggers {

View File

@@ -1,19 +0,0 @@
package com.spring.infra.batch;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public abstract class AbstractBatchConfig {
@Autowired
protected JobBuilderFactory jobBuilderFactory;
@Autowired
protected StepBuilderFactory stepBuilderFactory;
}

View File

@@ -6,8 +6,6 @@ import org.quartz.Job;
import org.quartz.Scheduler; import org.quartz.Scheduler;
import org.quartz.spi.JobFactory; import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle; import org.quartz.spi.TriggerFiredBundle;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -24,19 +22,6 @@ public class QuartzConfig {
private final DataSource dataSource; private final DataSource dataSource;
private final PlatformTransactionManager transactionManager; private final PlatformTransactionManager transactionManager;
/**
* JobRegistry 에 Job 을 자동으로 등록하기 위한 설정.
*
* @param jobRegistry ths Spring Batch Job Registry
* @return JobRegistry BeanPostProcessor
*/
@Bean
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
var jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
return jobRegistryBeanPostProcessor;
}
/** /**
* Quartz Schedule Job 에 의존성 주입 * Quartz Schedule Job 에 의존성 주입
* *
@@ -55,10 +40,8 @@ public class QuartzConfig {
/** /**
* Scheduler 전체를 관리하는 Manager. * Scheduler 전체를 관리하는 Manager.
* *
* @param datasource Spring datasource * @param jobFactory job factory
* @param quartzProperties quartz config
* @return the scheduler factory bean * @return the scheduler factory bean
* @throws Exception the exception
*/ */
@Bean @Bean
SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) { SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {

View File

@@ -5,36 +5,34 @@ import org.quartz.JobExecutionException;
import org.springframework.batch.core.Job; import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.JobLocator; import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class QuartzJobLauncher extends QuartzJobBean { public class QuartzJobLauncher extends QuartzJobBean {
private final JobLauncher jobLauncher;
private final JobRegistry jobRegistry;
private String jobName; private String jobName;
private JobLauncher jobLauncher;
private JobLocator jobLocator;
public void setJobName(String jobName) { public void setJobName(String jobName) {
this.jobName = jobName; this.jobName = jobName;
} }
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
public void setJobLocator(JobLocator jobLocator) {
this.jobLocator = jobLocator;
}
@Override @Override
protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException { protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException {
try { try {
Job job = jobLocator.getJob(jobName); Job job = jobRegistry.getJob(jobName);
JobParameters params = new JobParametersBuilder() JobParameters params = new JobParametersBuilder()
.addString("JobID", String.valueOf(System.currentTimeMillis())) .addString("JobID", String.valueOf(System.currentTimeMillis()))
.toJobParameters(); .toJobParameters();
jobLauncher.run(job, params); jobLauncher.run(job, params);
} catch (Exception e) { } catch (Exception e) {
throw new JobExecutionException(e); throw new JobExecutionException(e);

View File

@@ -10,43 +10,34 @@ import org.quartz.Scheduler;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
import org.quartz.Trigger; import org.quartz.Trigger;
import org.quartz.TriggerBuilder; import org.quartz.TriggerBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component @Component
public class QuartzJobRegistrar implements ApplicationContextAware, InitializingBean { @RequiredArgsConstructor
public class QuartzJobRegistrar implements ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext applicationContext; private final Scheduler scheduler;
private Scheduler scheduler; private final ApplicationContext applicationContext;
public QuartzJobRegistrar(Scheduler scheduler) {
this.scheduler = scheduler;
}
@Override @Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { public void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
this.applicationContext = applicationContext; for (String beanName : applicationContext.getBeanDefinitionNames()) {
} Object bean = applicationContext.getBean(beanName);
@Override
public void afterPropertiesSet() {
registerQuartzJobs();
}
private void registerQuartzJobs() {
applicationContext.getBeansWithAnnotation(QuartzJob.class).forEach((beanName, bean) -> {
Class<?> beanClass = bean.getClass(); Class<?> beanClass = bean.getClass();
for (Method method : beanClass.getMethods()) { for (Method method : beanClass.getDeclaredMethods()) {
QuartzJob quartzJobAnnotation = method.getAnnotation(QuartzJob.class); QuartzJob quartzJobAnnotation = AnnotationUtils.findAnnotation(method, QuartzJob.class);
if (quartzJobAnnotation != null) { if (quartzJobAnnotation != null) {
registerQuartzJob(quartzJobAnnotation, method.getName()); registerQuartzJob(quartzJobAnnotation, method.getName());
} }
} }
}); }
} }
private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) { private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) {
@@ -55,6 +46,7 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing
Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail); Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail);
scheduler.scheduleJob(jobDetail, trigger); scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) { } catch (SchedulerException e) {
e.printStackTrace();
throw new IllegalStateException("Error scheduling Quartz job", e); throw new IllegalStateException("Error scheduling Quartz job", e);
} }
} }
@@ -62,8 +54,6 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing
private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) { private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) {
JobDataMap jobDataMap = new JobDataMap(); JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("jobName", jobName); jobDataMap.put("jobName", jobName);
jobDataMap.put("jobLauncher", applicationContext.getBean("jobLauncher"));
jobDataMap.put("jobLocator", applicationContext.getBean("jobLocator"));
return JobBuilder.newJob(QuartzJobLauncher.class) return JobBuilder.newJob(QuartzJobLauncher.class)
.withIdentity(quartzJobAnnotation.name()) .withIdentity(quartzJobAnnotation.name())
.setJobData(jobDataMap) .setJobData(jobDataMap)

View File

@@ -54,9 +54,7 @@ public class QuartzProperties {
private void addProperties(String prefix, Object object, Properties properties) { private void addProperties(String prefix, Object object, Properties properties) {
Arrays.stream(object.getClass().getDeclaredFields()) Arrays.stream(object.getClass().getDeclaredFields())
.filter(field -> !Modifier.isStatic(field.getModifiers())) .filter(field -> !Modifier.isStatic(field.getModifiers()))
.forEach(field -> { .forEach(field -> setProperties(prefix, object, properties, field));
setProperties(prefix, object, properties, field);
});
} }
private void setProperties(String prefix, Object object, Properties properties, Field field) { private void setProperties(String prefix, Object object, Properties properties, Field field) {

View File

@@ -1,5 +1,7 @@
package com.spring.infra.security.config; package com.spring.infra.security.config;
import java.util.List;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@@ -29,7 +31,7 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SecurityConfig { public class SecurityConfig {
public static final String PERMITTED_URI[] = {"/api/auth/**", "/signIn"}; private static final String[] PERMITTED_URI = {"/favicon.ico", "/api/auth/**", "/signIn", "/h2-console/**"};
@Bean @Bean
SecurityFilterChain securityFilterChain( SecurityFilterChain securityFilterChain(
@@ -47,20 +49,23 @@ public class SecurityConfig {
.requestMatchers(PERMITTED_URI).permitAll() .requestMatchers(PERMITTED_URI).permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.logout((logout) -> logout .logout(logout -> logout
.logoutSuccessUrl("/signIn") .logoutSuccessUrl("/signIn")
.invalidateHttpSession(true)) .invalidateHttpSession(true))
.sessionManagement(session -> session .sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
) )
.addFilterBefore(new JwtAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtAuthenticationFilter(tokenService, List.of(PERMITTED_URI)), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(ex -> ex.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler)); .exceptionHandling(ex -> ex
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
);
return http.build(); return http.build();
} }
@Bean @Bean
WebSecurityCustomizer ignoringCustomizer() { WebSecurityCustomizer ignoringCustomizer() {
return (web) -> web.ignoring().requestMatchers("/h2-console/**"); return web -> web.ignoring().requestMatchers("/h2-console/**");
} }
@Bean @Bean

View File

@@ -1,6 +1,7 @@
package com.spring.infra.security.filter; package com.spring.infra.security.filter;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -20,11 +21,18 @@ import lombok.RequiredArgsConstructor;
public final class JwtAuthenticationFilter extends OncePerRequestFilter { public final class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenService jwtTokenService; private final JwtTokenService jwtTokenService;
private final List<String> permitAllUrls;
@Override @Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
String requestURI = request.getRequestURI();
if (permitAllUrls.stream().anyMatch(requestURI::startsWith)) {
filterChain.doFilter(request, response);
return;
}
String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX); String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX);
if (jwtTokenService.validateAccessToken(accessToken)) { if (jwtTokenService.validateAccessToken(accessToken)) {
setAuthenticationToContext(accessToken); setAuthenticationToContext(accessToken);

View File

@@ -21,11 +21,10 @@ public class JwtTokenService {
private final JwtTokenUtil jwtTokenUtil; private final JwtTokenUtil jwtTokenUtil;
private final JwtTokenGenerator jwtTokenGenerator; private final JwtTokenGenerator jwtTokenGenerator;
private final UserPrincipalService userPrincipalService; private final UserPrincipalService userPrincipalService;
private final Key accessSecretKey;
private final Key ACCESS_SECRET_KEY; private final Key refreshSecretKey;
private final Key REFRESH_SECRET_KEY; private final long accessExpiration;
private final long ACCESS_EXPIRATION; private final long refreshExpiration;
private final long REFRESH_EXPIRATION;
public JwtTokenService( public JwtTokenService(
JwtTokenUtil jwtTokenUtil, JwtTokenUtil jwtTokenUtil,
@@ -36,22 +35,22 @@ public class JwtTokenService {
this.jwtTokenUtil = jwtTokenUtil; this.jwtTokenUtil = jwtTokenUtil;
this.jwtTokenGenerator = jwtTokenGenerator; this.jwtTokenGenerator = jwtTokenGenerator;
this.userPrincipalService = userPrincipalService; this.userPrincipalService = userPrincipalService;
this.ACCESS_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret()); this.accessSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret());
this.REFRESH_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret()); this.refreshSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret());
this.ACCESS_EXPIRATION = jwtProperties.getAccessToken().getExpiration(); this.accessExpiration = jwtProperties.getAccessToken().getExpiration();
this.REFRESH_EXPIRATION = jwtProperties.getRefreshToken().getExpiration(); this.refreshExpiration = jwtProperties.getRefreshToken().getExpiration();
} }
public String generateAccessToken(HttpServletResponse response, Authentication authentication) { public String generateAccessToken(HttpServletResponse response, Authentication authentication) {
String accessToken = jwtTokenGenerator.generateAccessToken(authentication); String accessToken = jwtTokenGenerator.generateAccessToken(authentication);
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, ACCESS_EXPIRATION / 1000); ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, accessExpiration / 1000);
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString()); response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
return accessToken; return accessToken;
} }
public String generateRefreshToken(HttpServletResponse response, Authentication authentication) { public String generateRefreshToken(HttpServletResponse response, Authentication authentication) {
String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication); String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication);
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, REFRESH_EXPIRATION / 1000); ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, refreshExpiration / 1000);
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString()); response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
return refreshToken; return refreshToken;
} }
@@ -67,23 +66,23 @@ public class JwtTokenService {
} }
public boolean validateAccessToken(String token) { public boolean validateAccessToken(String token) {
return jwtTokenUtil.getTokenStatus(token, ACCESS_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED; return jwtTokenUtil.getTokenStatus(token, accessSecretKey) == JwtTokenStatus.AUTHENTICATED;
} }
public boolean validateRefreshToken(String token) { public boolean validateRefreshToken(String token) {
return jwtTokenUtil.getTokenStatus(token, REFRESH_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED; return jwtTokenUtil.getTokenStatus(token, refreshSecretKey) == JwtTokenStatus.AUTHENTICATED;
} }
public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) { public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) {
Cookie[] cookies = request.getCookies(); Cookie[] cookies = request.getCookies();
if (cookies == null) { if (cookies == null) {
throw new RuntimeException("JWT_TOKEN_NOT_FOUND"); throw new IllegalStateException("JWT_TOKEN_NOT_FOUND");
} }
return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix); return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix);
} }
public Authentication getAuthentication(String token) { public Authentication getAuthentication(String token) {
UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, ACCESS_SECRET_KEY)); UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, accessSecretKey));
return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities());
} }

View File

@@ -45,11 +45,11 @@ spring:
batch: batch:
jdbc: jdbc:
initialize-schema: never initialize-schema: always
quartz: quartz:
jdbc: jdbc:
initialize-schema: never initialize-schema: always
wait-for-jobs-to-complete-on-shutdown: true wait-for-jobs-to-complete-on-shutdown: true
job-store-type: jdbc job-store-type: jdbc
properties: properties: