1๏ธโฃ ํด๋ผ์ด์ธํธ(์ ์ )๊ฐ ๋ก๊ทธ์ธ์ ์๋
2๏ธโฃ AuthenticationFilter๋ AuthenticationManager, AuthenticationProvider(s), UserDetailsService๋ฅผ ํตํด DB์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฝ์ด์ด
3๏ธโฃ UserDetailsService๋ ๋ก๊ทธ์ธํ ID์ ํด๋นํ๋ ์ ๋ณด๋ฅผ DB์์ ์ฝ์ด๋ค์ฌ UserDetails๋ฅผ ๊ตฌํํ ๊ฐ์ฒด๋ก ๋ฐํ
4๏ธโฃ ์คํ๋ง ์ํ๋ฆฌํฐ๋ ์ธ๋ฉ๋ชจ๋ฆฌ ์ธ์
์ ์ฅ์์ธ SecurityContextHolder ์ UserDetails์ ๋ณด๋ฅผ ์ ์ฅ
5๏ธโฃ ํด๋ผ์ด์ธํธ(์ ์ )์๊ฒ session ID(JSESSION ID)์ ํจ๊ป ์๋ต
6๏ธโฃ ์ดํ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์์ฒญ ์ฟ ํค์์ JSESSION ID์ ๋ณด๋ฅผ ํตํด ์ด๋ฏธ ๋ก๊ทธ์ธ ์ ๋ณด๊ฐ ์ ์ฅ๋์ด ์๋ ์ง ํ์ธ
1๏ธโฃ. ํด๋ผ์ด์ธํธ ์์ฒญ
2๏ธโฃ. ์์ฒญ URI ๊ฒฝ๋ก ๊ธฐ๋ฐ ํํฐ ์ธ์คํด์ค์ ์๋ธ๋ฆฟ์ด ํฌํจ๋ FilterChain์์ฑ
3๏ธโฃ. ์์
์ํ
๋ค์ํ ๊ธฐ๋ฅ์ ๊ฐ์ง ํํฐ๋ค์ 10๊ฐ ์ด์ ๊ธฐ๋ณธ ์ ๊ณต, ์ด ๋ฌถ์์ Security filter Chain์ด๋ผ๊ณ ํจ
DelegationFilterProxy์ ๋ฐ๋ก ๋ฑ๋กํ์ง ์๊ณ FilterChainProxy์์ Security Filter Chain์ ๋ฑ๋กํจ
SecurityContextPersistenceFilter
SecurityContextRepository์์ SecurityContext๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋ ์ ์ฅํ๋ ์ญํ
LogoutFilter
์ค์ ๋ ๋ก๊ทธ์์ URL๋ก ์ค๋ ์์ฒญ์ ๊ฐ์ํ๋ฉฐ, ํด๋น ์ ์ ๋ฅผ ๋ก๊ทธ์์ ์ฒ๋ฆฌ
UsernamePasswordAuthenticationFilter
(์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ฌ์ฉํ๋ form ๊ธฐ๋ฐ ์ธ์ฆ) ์ค์ ๋ ๋ก๊ทธ์ธ URL๋ก ์ค๋ ์์ฒญ ๊ฐ์, ์ ์ ์ธ์ฆ ์ฒ๋ฆฌ
BasicAuthenticationFilter
HTTP ๊ธฐ๋ณธ ์ธ์ฆ ํค๋๋ฅผ ๊ฐ์ํ์ฌ ์ฒ๋ฆฌ
RequestCacheAwareFilter
๋ก๊ทธ์ธ ์ฑ๊ณต ํ ์๋ ์์ฒญ ์ ๋ณด๋ฅผ ์ฌ๊ตฌ์ฑํ๊ธฐ ์ํด ์ฌ์ฉ
SecurityContextHolderAwareRequestFilter
HttpServletRequestWrapper๋ฅผ ์์ํ SecurityContextHolderAwareRequestWapper ํด๋์ค๋ก HttpServletRequest ์ ๋ณด๋ฅผ ๊ฐ์ธ์ฃผ๊ณ Security
ContextHolderAwareRequestWrapper ํด๋์ค๋ ํํฐ ์ฒด์ธ์์ ๋ค์ ํํฐ๋ค์๊ฒ ๋ถ๊ฐ์ ๋ณด ์ ๊ณต
AnonymousAuthenticationFilter
์ด ํํฐ๊ฐ ํธ์ถ๋๋ ์์ ๊น์ง ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์ธ์ฆ๋์ง ์์๋ค๋ฉด ์ธ์ฆํ ํฐ์ ์ฌ์ฉ์๊ฐ ์ต๋ช
์ฌ์ฉ์๋ก ๋ํ๋จ
SessionManagementFilter
์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ด๋ จ๋ ๋ชจ๋ ์ธ์
์ ์ถ์
ExceptionTranslationFilter
๋ณดํธ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์ค์ ๋ฐ์ํ ์ ์๋ ์์ธ๋ฅผ ์์ํ๊ฑฐ๋ ์ ๋ฌํ๋ ์ญํ
FilterSecurityInterceptor
AccessDecisionManager๋ก ๊ถํ๋ถ์ฌ ์ฒ๋ฆฌ๋ฅผ ์์ํจ์ผ๋ก์จ ์ ๊ทผ ์ ์ด ๊ฒฐ์ ์ ์ฝ๊ฒ ํด์ค
implementation 'org.springframework.boot:spring-boot-starter-security'
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig {
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf((csrf) -> csrf.disable())
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(exceptionHandling -> exceptionHandling
.accessDeniedHandler(jwtAccessDeniedHandler)
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
)
.cors(cors -> cors.disable())
.sessionManagement(httpSecuritySessionManagementConfigurer ->
httpSecuritySessionManagementConfigurer
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(b -> b.disable())
.authorizeHttpRequests(
(authorizeHttpRequests) ->
authorizeHttpRequests
.requestMatchers(
"/signup",
"/photo/list",
"/photo/like",
"/meeting/list",
"/meeting/info",
"/people-count",
"/api/authenticate",
"/meeting/info/**",
"/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(
formLogin -> formLogin.disable())
.logout(logout -> logout.logoutUrl("/logout"))
.apply(new JwtSecurityConfig(tokenProvider));
return http.build();
}
}
csrf.disable()
์ฌ์ดํธ๊ฐ ์์ฒญ ์์กฐ ๋ฐฉ์ง ๋นํ์ฑํ
cors.disable()
๋ค๋ฅธ ์ถ์ฒ๋ฅผ ๊ฐ์ง ์์์ ์ ๊ทผ ๋นํ์ฑํ
httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
์คํ๋ง์ด ์ธ์
์ ์ฌ์ฉํ์ง ์๊ณ ์์ฑ๋ ํ์ง ์์
httpBasic(b -> b.disable()
๊ธฐ๋ณธ ์ธ์ฆ ๋ก๊ทธ์ธ์ ์ฌ์ฉํ์ง ์์
authorizeHttpRequests.requestMatchers("๊ฒฝ๋ก").permitAll()
๊ฒฝ๋ก๋ณ๋ก ๊ถํ์ ์ฒ๋ฆฌํ์ง๋ง permitAll()๋ ๊ฒฝ๋ก๋ ๊ถํ์ ์๊ด์์ด ๋ชจ๋์๊ฒ ํ์ฉ๋จ
anyRequest().authenticated()
ํ์ฉ๋ ๊ฒฝ๋ก๋ฅผ ์ ์ธํ ๋ชจ๋ ์์ฒญ์ ์ธ์ฆ ๋์ด์ผ ํจ
formLogin.disable()
formLogin์ ์ฌ์ฉํ์ง ์์
@Component("userDetailsService")
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Slf4j
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
log.info("loadUserByUsername ์คํ๋จ");
User user = userRepository.findByUserStrId(userId);
if(user == null) {
throw new UserNotFoundException(userId+"๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค");
}
return new PrincipalDetails(user);
}
}
@NoArgsConstructor
@Getter
@Setter
public class PrincipalDetails implements UserDetails, OAuth2User{
private User user;
private Map<String, Object> attributes;
public PrincipalDetails(User user) {
this.user = user;
}
public PrincipalDetails(User user, Map<String, Object> attributes) {
this.user = user;
this.attributes = attributes;
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getName() {
return null;
}
}
์ถ์ฒ