-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAuthConfig.java
More file actions
132 lines (107 loc) · 6.01 KB
/
AuthConfig.java
File metadata and controls
132 lines (107 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.kustacks.kuring.auth;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kustacks.kuring.admin.application.service.AdminDetailsService;
import com.kustacks.kuring.auth.authorization.AuthenticationPrincipalArgumentResolver;
import com.kustacks.kuring.auth.context.SecurityContextPersistenceFilter;
import com.kustacks.kuring.auth.handler.AuthenticationFailureHandler;
import com.kustacks.kuring.auth.handler.AuthenticationSuccessHandler;
import com.kustacks.kuring.auth.handler.LoginAuthenticationFailureHandler;
import com.kustacks.kuring.auth.handler.LoginAuthenticationSuccessHandler;
import com.kustacks.kuring.auth.handler.UserRegisterFailureHandler;
import com.kustacks.kuring.auth.handler.UserRegisterSuccessHandler;
import com.kustacks.kuring.auth.interceptor.AdminTokenAuthenticationFilter;
import com.kustacks.kuring.auth.interceptor.BearerTokenAuthenticationFilter;
import com.kustacks.kuring.auth.interceptor.FirebaseTokenAuthenticationFilter;
import com.kustacks.kuring.auth.interceptor.UserRegisterNonChainingFilter;
import com.kustacks.kuring.auth.token.JwtTokenProvider;
import com.kustacks.kuring.common.properties.ServerProperties;
import com.kustacks.kuring.message.application.port.in.FirebaseWithUserUseCase;
import com.kustacks.kuring.user.adapter.out.persistence.UserPersistenceAdapter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Configuration
@RequiredArgsConstructor
public class AuthConfig implements WebMvcConfigurer {
private final AdminDetailsService adminDetailsService;
private final JwtTokenProvider jwtTokenProvider;
private final ObjectMapper objectMapper;
private final ServerProperties serverProperties;
private final FirebaseWithUserUseCase firebaseService;
private final UserPersistenceAdapter userPersistenceAdapter;
@Value("${cors.allowed-origins}")
private List<String> allowedOrigins;
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
CorsConfiguration config = new CorsConfiguration();
List<String> dynamicOrigins = new ArrayList<>(allowedOrigins);
dynamicOrigins.add("http://localhost:[*]");
dynamicOrigins.add("http://127.0.0.1:[*]");
config.setAllowedOriginPatterns(dynamicOrigins);
config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*")); // 모든 요청 헤더 허용
// [보안 권장] 모든 응답 헤더를 노출하는 대신 필요한 헤더만 명시적으로 노출합니다.
// 예를 들어, 프론트에서 Authorization 헤더에 담긴 토큰을 읽어야 할 경우 아래와 같이 설정합니다.
config.setExposedHeaders(List.of("Authorization", "Location"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(new CorsFilter(source));
registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // [수정] 필터 순서를 가장 높게 설정하여 다른 필터보다 먼저 실행되도록 합니다.
return registration;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SecurityContextPersistenceFilter());
registry.addInterceptor(new AdminTokenAuthenticationFilter(
adminDetailsService, passwordEncoder(), objectMapper,
adminLoginSuccessHandler(), adminLoginFailureHandler()))
.addPathPatterns("/api/v2/admin/login");
registry.addInterceptor(new UserRegisterNonChainingFilter(
serverProperties, firebaseService, userPersistenceAdapter, objectMapper,
userRegisterSuccessHandler(), userRegisterFailureHandler()))
.addPathPatterns("/api/v2/users");
registry.addInterceptor(new BearerTokenAuthenticationFilter(jwtTokenProvider))
.addPathPatterns("/api/v2/admin/**");
registry.addInterceptor(new FirebaseTokenAuthenticationFilter(firebaseService, objectMapper))
.addPathPatterns("/api/v2/users/**");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
AuthenticationSuccessHandler adminLoginSuccessHandler() {
return new LoginAuthenticationSuccessHandler(jwtTokenProvider, objectMapper);
}
@Bean
AuthenticationFailureHandler adminLoginFailureHandler() {
return new LoginAuthenticationFailureHandler(objectMapper);
}
@Bean
AuthenticationSuccessHandler userRegisterSuccessHandler() {
return new UserRegisterSuccessHandler(objectMapper);
}
@Bean
AuthenticationFailureHandler userRegisterFailureHandler() {
return new UserRegisterFailureHandler(objectMapper);
}
}