JiwonDev

Spring Security #3 ์•„ํ‚คํ…์ฒ˜ ์ดํ•ดํ•˜๊ธฐ, ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์›๋ฆฌ

by JiwonDev
 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ - Spring Boot ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” Spring Security - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์ดˆ๊ธ‰์—์„œ ์ค‘.๊ณ ๊ธ‰์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ API ์‚ฌ์šฉ๋ฒ•๊ณผ ๋‚ด๋ถ€ ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ•™์Šตํ•˜๊ฒŒ ๋˜๊ณ  ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋ฅผ ์™„์„ฑํ•ด ๋‚˜๊ฐ์œผ๋กœ์จ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ์ธ์ฆ๊ณผ

www.inflearn.com

ํ•„ํ„ฐ๋Š” ์ž๋ฐ” ์›น ํ‘œ์ค€์ธ Servlet 2.3๋ฒ„์ „๋ถ€ํ„ฐ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์ด๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

 

2022.03 ์ถ”๊ฐ€(๋ฆฌ๋ทฐ๋‚ด์šฉ)

Provider๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ , ๊ทธ๋ƒฅ ๊ธฐ๋ณธ AuthenticationManager.authenticate(new token())์„ ํ˜ธ์ถœํ•ด๋ฒ„๋ฆฐ๊ฒฝ์šฐ

 

๋‹จ์ˆœํžˆ ํŒจ์Šค์›Œ๋“œ๋ฅผ ๋น„๊ตํ•˜๋Š” ๋กœ์ง์ด๋ผ ๋”ฐ๋กœ Provider๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ , ์‹œํ๋ฆฌํ‹ฐ์˜ ๊ธฐ๋ณธ ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‚˜์ค‘์— ์ถ”๊ฐ€์ ์ธ ์ธ์ฆ์ด ํ•„์š”ํ•˜๊ฒŒ ๋˜๋ฉด
public class CustomAuthenticationProvider implements AuthenticationProvider ๊ฐ™์€ ๊ฑธ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜€


์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ์•Œ์•„์„œ ํ•ด์ค€๋‹ค๋ผ๊ณ  ์„ค๋ช…ํ•˜๋‹ˆ ์กฐ๊ธˆ ๋ถˆ์•ˆํ•ด์„œ, ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ๋œฏ์–ด๋ดค๋Š”๋ฐ

1. ๋กœ๊ทธ์ธ ๊ณผ์ •์—์„œ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • authenticationManager์˜ ๊ตฌํ˜„์ฒด์ธ ProviderManager๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ํ† ํฐ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(username, password)
        );

 

2. ๋”ฐ๋กœ ๋“ฑ๋กํ•ด๋‘” ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๊ธฐ๋ณธ ํ”„๋กœ๋ฐ”์ด๋”์ธ DaoAuthenticationProvider ๊ฐ€ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด ํ”„๋กœ๋ฐ”์ด๋”๋Š” ๋งค๋‹ˆ์ €์— ๋“ฑ๋ก๋œ UserDetailsService์™€ PasswordEncoder๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    // SecurityConfig.java
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(accountDetailsService).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(jwtAuthenticationProvider); // ์ด๊ฑด JwtAuthToken ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Provider
    }

 

  • DaoAuthenticationProvider ๋Š” ์•„๋ž˜ ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๋ฉฐ, UsernamePasswordAuthenticationToken ๋ฅผ support ํ•ฉ๋‹ˆ๋‹ค.
public abstract class AbstractUserDetailsAuthenticationProvider{
... ์ƒ๋žต ...
	@Override
	public boolean supports(Class<?> authentication) {
		return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
	}

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        ...
      try {
		      this.preAuthenticationChecks.check(user);
	              additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
	 	  } 
	    catch (AuthenticationException ex) {
            ...
          }
        return createSuccessAuthentication(principalToReturn, authentication, user);
      }
}

 

3. ์ฆ‰, Provider.authenticate(...)๊ฐ€ ์‹คํ–‰๋˜๋ฉด, ์•„๋ž˜์˜ ๋กœ์ง์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
... ์ƒ๋žต ...
	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
		if (authentication.getCredentials() == null) {
			this.logger.debug("Failed to authenticate since no credentials provided");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
		String presentedPassword = authentication.getCredentials().toString();
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
			this.logger.debug("Failed to authenticate since password does not match stored value");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
	}
...
}	

-------------------------------------------------------------

 

๐Ÿ’ญ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๋™์ž‘๊ณผ์ •(๋ณต์Šต)

๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์˜ ๊ฒฝ์šฐ, FilterChain์„ ๊ตฌ์„ฑํ•˜์—ฌ ์„œ๋ธ”๋ฆฟ์ด ์‹คํ–‰๋˜๊ธฐ ์ „ ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋œ๋‹ค.

 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๊ฒฝ์šฐ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์ฒด์ธ์— DelegatingFilterProxy๋ฅผ ๋“ฑ๋กํ•œ๋‹ค. ์ด๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์˜ ๊ตฌํ˜„์ฒด์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ํ•„ํ„ฐ๊ฐ€ SecurityFilterChain์„ ํ˜ธ์ถœํ•˜๊ณ , ์Šคํ”„๋ง์— ๋“ฑ๋ก๋œ ๋นˆ์„ ๊ฐ€์ ธ์™€์„œ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๊ฒŒ ๋œ๋‹ค.  

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // Lazily get Filter that was registered as a Spring Bean
    // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
    Filter delegate = getFilterBean(someBeanName);
    // delegate work to the Spring Bean
    delegate.doFilter(request, response);
}

DelegatingFilterProxy ๋Š” ์Šคํ”„๋ง ๋นˆ์ด ์•„๋‹ˆ๋‹ค. ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋ผ์„œ ์‹ค์ œ ๋™์ž‘์€ FilterChainProxy(์Šคํ”„๋ง Bean)์— ์œ„์ž„ํ•œ๋‹ค.

์ฆ‰ DelegatingFilter๋Š” ๋ณด์•ˆ๊ณผ ๊ด€๋ จ๋œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

@EnableWebSecurity๋ฅผ ์ ์œผ๋ฉด ์•ฑ ์‹œ์ž‘์‹œ์— SecurityFilterAutoConfiguration ๊ฐ์ฒด๊ฐ€ DelegatingFilter๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
์ดํ›„ WebSecurityConfiguration๊ฐ€ springSecurityFilterChain ์ด๋ฆ„์˜ ์Šคํ”„๋ง๋นˆ(=FilterChainProxy ํด๋ž˜์Šค)์„ ๋“ฑ๋กํ•œ๋‹ค.
์ „์ฒด์ ์ธ ๋™์ž‘๊ณผ์ •์€ ์ด๋Ÿฌํ•˜๋‹ค. DelegatingFilterProxy๋งŒ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์ด๊ณ , ๋‚˜๋จธ์ง„ AppContext์—์„œ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.

 

 

  • FilterChainProxy๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ ์ฒด์ธ์— ์œ„์ž„ํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.
    [์„œ๋ธ”๋ฆฟ โžก ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ์ง„์ž…์ ]์ด๋ฉฐ, ์„œ๋ธ”๋ฆฟ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ํ•ด๋‹น ๊ฐ์ฒด์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ด๋ฏธ์ง€ ์ถœ์ฒ˜ https://limdevbasic.tistory.com/19

 

  • FilterChainProxy๋Š” ์•ฑ๋‹น ํ•˜๋‚˜์ง€๋งŒ, SecurityFilterChain์€ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    ์ฆ‰ ์•„๋ž˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ DelegatingFilterProxy(ํ•„ํ„ฐ)์— ์žˆ๋Š” FilterChainProxy(์Šคํ”„๋ง ๋นˆ)์—์„œ
    HTTP URL์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ฒด์ธ์ด ์ž‘๋™ํ•˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    SecurityFilterChain์€ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    FilterChainProxy ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์„ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

๐Ÿ“‘ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ์˜ ๋™์ž‘๊ณผ์ •

์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ ๊ทธ๋ฆผ์œผ๋กœ ๊ทธ๋ ค๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

WebSecurityConfigurerAdpater๋ฅผ ํ†ตํ•ด HttpSecurity๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@Order(0)
public class SecurityConfig1 extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/admin/**")
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic(); // HTTP BASIC ๋ฐฉ์‹
    }
}

//.. ๋‹ค๋ฅธ ํŒจํ‚ค์ง€ ..//
@Configuration
@Order(1) // ์ด๊ฑฐ ์—†์œผ๋ฉด IllegalStateException: @Order on WebSecurityConfigurers must be unique. ๋ฐœ์ƒ
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().permitAll()
            .and()
            .formLogin(); // FORM LOGIN ๋ฐฉ์‹
    }
}

FilterChainProxy๋Š” Order ์ˆœ์„œ๋Œ€๋กœ ๋จผ์ € ๋น„๊ตํ•œ๋‹ค. (๋น„๊ตํ•˜๋Š”๋ฐ ๊ฐ ํ•„ํ„ฐ์˜ RuestMacher๋ฅผ ์‚ฌ์šฉ)

์˜ˆ์ œ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ•„ํ„ฐ ์ฒด์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, Order(~) ์ˆœ์„œ๋Š” ๋„“์€ ๋ฒ”์œ„์˜ ๋ณด์•ˆ์„ค์ •์„ ๋จผ์ € ์ ์šฉํ•ด์ฃผ๋Š”๊ฒŒ ์ข‹๋‹ค.

์ˆซ์ž๊ฐ€ ๋‚ฎ์„ ์ˆ˜๋ก Order(0) ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค.

 

์‹ค์ œ ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณด๊ธฐ (FilterChainProxy)

๋”๋ณด๊ธฐ

FilterChainProxy ๊ฐ์ฒด๋Š” ๋“ฑ๋ก๋œ ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์„ filters๋ผ๋Š” ๋ฆฌ์ŠคํŠธ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

์‹ค์ œ FilterChainProxy๋ฅผ ๋ณด๋ฉด ๋จผ์ € Request ์š”์ฒญ์— ๋”ฐ๋ผ ์•Œ๋งž์€ ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์„ ์„ ํƒํ•œ๋‹ค.

๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ๋“ค์„ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ํ•˜๋‚˜์”ฉ request์™€ ๋น„๊ต(matches)ํ•œ๋‹ค.

๊ทธ ์ค‘ ์ œ์ผ ๋จผ์ € ์ฐพ์€ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ,
๋น„๊ตํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ matches ๋ฉ”์„œ๋“œ๋ฅผ ๊นŒ๋ณด๋ฉด ํ•ด๋‹น ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ ์ฒด์ธ์˜ requestMatcher ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•œ๋‹ค.

 

๐Ÿ“Œ ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šคํ”„๋ง์‹œํ๋ฆฌํ‹ฐ ์„ค์ •์„ ๋งŒ๋“ค ๋•Œ(=์ฒด์ธ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ) @Order๊ฐ€ ํ•„์ˆ˜์ธ ๊ฒƒ์ด๋‹ค.

URL ์š”์ฒญ์ด ๊ฐ™๋‹ค๋ฉด @Order์— ๋“ฑ๋ก๋œ ์ˆœ์„œ๋Œ€๋กœ ๋จผ์ € ํ•„ํ„ฐ๊ฐ€ ๋งค์นญ๋œ๋‹ค. 

 

์•ž์—์„œ ๋ฐฐ์› ์ง€๋งŒ ๊ฐ๊ฐ์˜ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์€, ๋”ฐ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š์•„๋„ ๋งŽ์€ ๊ธฐ๋ณธ ํ•„ํ„ฐ๊ฐ€ ์ ์šฉ๋˜์–ด์žˆ๋‹ค.

์ด ํ•„ํ„ฐ๋“ค๋„ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ( chain.doFilter() )์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋ฉฐ ์ˆœ์„œ๊ฐ€ ์žˆ๋‹ค. ์ ์šฉ๋˜๋Š” ์ˆœ์„œ์™€ ์ข…๋ฅ˜๋Š” ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

์•Œ๊ณ ์žˆ์œผ๋ฉด ์ข‹๊ธดํ•œ๋ฐ, ์›Œ๋‚™ ์ข…๋ฅ˜๊ฐ€ ๋งŽ๊ธฐ๋„ํ•˜๊ณ  ๋ชจ๋ฅธ๋‹ค๊ณ ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง€๋Š” ์•Š๋Š”๋‹ค.

๋””๋ฒ„๊ทธ๋ฅผ ์ฐ์–ด๋ณด๋ฉด, http.formLogin()์€ 13๊ฐœ์˜ ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์ด ์ˆœ์„œ๋Œ€๋กœ ๋™์ž‘ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
๋”ฐ๋กœ ํ•„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜์ง€ ์•Š๋”๋ผ๋„, ์‹œํ๋ฆฌํ‹ฐ ์‚ฌ์šฉ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ถ”๊ฐ€๋˜๋Š” ํ•„ํ„ฐ๋“ค์ด ์žˆ๋‹ค.

 

 

๐Ÿ’ญ ์ธ์ฆ(Authentication)

์ธ์ฆ์€ ๋กœ๊ทธ์ธ์ฒ˜๋Ÿผ, ๋‚ด๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ์ฆ๋ช…ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ธ์ฆ ์‹œ id์™€ password๋ฅผ HTTP์š”์ฒญ์— ๋‹ด๊ณ , ์„œ๋ฒ„์— ์ „๋‹ฌ๋œ๋‹ค.

์„œ๋ฒ„์—์„œ ์ธ์ฆ ํ›„, ์ธ์ฆ ๊ฐ์ฒด(User + ๊ถŒํ•œ์ •๋ณด)์— ๋‹ด์•„ SecurityContext์— ๋‹ด๊ณ  ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณตํ•ด์ค€๋‹ค.

Authentication authentication = SecurityContexHolder.getContext().getAuthentication()

์ด ๊ฐ์ฒด์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • principal : ์‚ฌ์šฉ์ž ์•„์ด๋”” ํ˜น์€ User ๊ฐ์ฒด๋ฅผ ์ €์žฅ
  • credentials : ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ (๋ณด์•ˆ์ƒ ์ธ์ฆ์ดํ›„ ์ธ์ฆ๊ฐ์ฒด์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ์•„์˜ˆ ๋น„์›Œ๋‘๊ธฐ๋„ ํ•จ)
  • authorities : ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ ๋ชฉ๋ก
  • details : ์ธ์ฆ ๋ถ€๊ฐ€ ์ •๋ณด (๋‚˜์ค‘์— ์–ธ๊ธ‰)
  • Authenticated : ์ธ์ฆ ์—ฌ๋ถ€

์ธ์ฆ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ณผ์ •

์ธ์ฆ์ •๋ณด๋Š” SecurityContext์— ๋‹ด๊ณ  ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณตํ•ด์ค€๋‹ค. ์ด๊ฒŒ ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ•œ๊ฑธ๊นŒ?

์Šคํ”„๋ง์‹œํ๋ฆฌํ‹ฐ์˜ AuthenticationProcessingFilter์—์„œ ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ์‹œํ๋ฆฌํ‹ฐ ์ปจํ…์ŠคํŠธ์— ์ธ์ฆ๊ฐœ์ฒด๋ฅผ ๋„ฃ๋Š”๋‹ค.

์ •ํ™•ํžˆ๋Š” ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ThreadLocal ๋ฉ”๋ชจ๋ฆฌ์— SecurityContextHolder๋ฅผ ๋‘๊ณ  static ๋ฉ”์„œ๋“œ๋กœ SecurityContext๋ฅผ ๊บผ๋‚ธ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ธ์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด HttpSession์— ์ธ์ฆ๊ฐœ์ฒด๋ฅผ ์ €์žฅํ•ด์„œ ์Šค๋ ˆ๋“œ๊ฐ€ ์—†์–ด์ง€๋”๋ผ๋„ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ SecurityContextHolder๋ฅผ ๊ฑฐ์น˜์ง€์•Š๊ณ , HttpSession์—์„œ SecurityContext ๊ฐ์ฒด๋ฅผ ๋ฐ”๋กœ ๊บผ๋‚ด์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

 

โœจ HttpSession์ด ๋ญ์˜€๋”๋ผ..?

๋”๋ณด๊ธฐ

HTTP๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„์—ฐ๊ฒฐ์„ฑ์„ ์ง€ํ–ฅํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰ ํ•ญ์ƒ ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์š”์ฒญ์— ๋”ฐ๋ฅธ ์‘๋‹ต ์ดํ›„์—๋Š” ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๋‚ด๊ฐ€ ์š”์ฒญ์„ 3๋ฒˆ ๋ณด๋‚ด๋”๋ผ๋„ ์„œ๋ฒ„ ์ž…์žฅ์—์„œ๋Š” ๋‹ค๋ฅธ์‚ฌ๋žŒ 3๋ช…์ด ๊ฐ๊ฐ ๋ณด๋‚ด๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ƒํƒœ๊ฐ€ ์—†์–ด์š”.

 

HTTP๋ฅผ ์ด์šฉํ•œ ์›น์—์„œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๋งŒ, ๋Œ€ํ‘œ์ ์œผ๋กœ HttpSession ๊ฐ์ฒด๋ฅผ ์ด์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„(WAS์˜ ์„œ๋ธ”๋ฆฟ์ปจํ…Œ์ด๋„ˆ)์—์„œ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‹จ์œ„๋กœ Session ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋ธŒ๋ผ์šฐ์ € ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” request ์•ˆ์— HttpSession ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , 

* ์ฐธ๊ณ ๋กœ session์„ ์š”์ฒญํ•˜์ง€ ์•Š์œผ๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ HttpSession ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ์ตœ์ ํ™”๋˜์–ด์žˆ์Œ.

ํ˜„์žฌ ์„œ๋ฒ„ ์„ธ์…˜ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ์„ธ์…˜์„ JSESSIONID ๋กœ ์ฐพ์•„์„œ ์—ฐ๊ฒฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค. 

 

์กฐ๊ธˆ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด

1. ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ Request๋งˆ๋‹ค HttpSession ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 
์ •ํ™•ํžˆ๋Š” httpServletRequest.getSession() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด HttpSession ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

1-1. ์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง์—์„œ๋„ HttpSession์„ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋งŒ HttpSession์„ @Autowired๋กœ ์‚ฌ์šฉํ•˜๋ฉด HttpSession ๊ฐ์ฒด๋ฅผ ํ”„๋ก์‹œ๋กœ ๋งŒ๋“ค์–ด์„œ Lazyํ•˜๊ฒŒ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. 
์ฆ‰ httpSession.setAttribute() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์— ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์š”์ฒญํ•˜๊ณ  ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
๋ฌผ๋ก  ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ๋ฐ”๋กœ ๋ฐ›์•„์˜ค๋ฉด method(HttpSession session) ์ฆ‰์‹œ HttpSession์„ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.


2. HttpSession ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์•ˆ์˜ ์„ธ์…˜๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์„ธ์…˜ ๋ฉ”๋ชจ๋ฆฌ๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‹จ์œ„๋กœ ๋งŒ๋“ค์–ด์ง€๋ฉฐ, JSESSIONID์„ ๊ธฐ์ค€์œผ๋กœ ๊ฐ ์„ธ์…˜๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
(์‹ค์ œ ํ†ฐ์บฃ์˜ ์„ธ์…˜์ƒ์„ฑ ์ฝ”๋“œ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด https://semtax.tistory.com/92 ์ฐธ๊ณ )

๋ฌผ๋ก  ์„ธ์…˜๋ฉ”๋ชจ๋ฆฌ๋„ ์„œ๋ฒ„์— ๋ถ€๋‹ด์ด ๋˜๊ธฐ๋•Œ๋ฌธ์—, ๋ณดํ†ต์€ ๋งˆ์ง€๋ง‰ ์š”์ฒญ์—์„œ๋ถ€ํ„ฐ 30~60๋ถ„์ •๋„๋งŒ ์œ ์ง€๋˜๋„๋ก ๋งŒ๋“ค์–ด๋‘ก๋‹ˆ๋‹ค.

 

๐Ÿ“‘ SecurityContextHolder๋ž€

๐Ÿ“ŒSecurityContext 

  • ๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋˜๋Š” ๋ณด๊ด€์†Œ๋กœ ํ•„์š” ์‹œ ์–ธ์ œ๋“ ์ง€ Authentication ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์–ด ์“ธ ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณต๋˜๋Š” ํด๋ž˜์Šค
  • ThreadLocal ์— ์ €์žฅ๋˜์–ด ์•„๋ฌด ๊ณณ์—์„œ๋‚˜ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค๊ณ„ํ•จ
  • ์ธ์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด ์„ธ์…˜ ์ €์žฅ์†Œ(HttpSession) ์— ์ €์žฅ๋˜์–ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ „์—ญ์ ์ธ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค

 

๐Ÿ“ŒSecurityContextHolder

SecurityContext ์ €์žฅ์†Œ์ด๋‹ค. Http ์„ธ์…˜์— ์žˆ๋Š” S.C๋ฅผ ๊บผ๋‚ด Holder์— ์ €์žฅํ•ด๋‘”๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์— ์žˆ๋Š” Holder ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์„œ ์œ„์น˜์™€ ์ƒ๊ด€์—†์ด ์ „์—ญ์ ์œผ๋กœ SecurityContext์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

SecurityContext์— ๋Œ€ํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด 3๊ฐ€์ง€ ์ €์žฅ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

import org.springframework.security.core.context.SecurityContextHolder;

SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHEADLOCAL);
  • MODE_THREADLOCAL(๊ธฐ๋ณธ๊ฐ’) : ์Šค๋ ˆ๋“œ๋‹น SecurityContext ๊ฐ์ฒด๋ฅผ ํ• ๋‹น
  • MODE_INHERITABLETHREADLOCAL : ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์™€ ์ž์‹ ์Šค๋ ˆ๋“œ์— ๊ด€ํ•˜์—ฌ ๋™์ผํ•œ SecurityContext ๋ฅผ ์œ ์ง€
  • MODE_GLOBAL :  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋‹จ ํ•˜๋‚˜์˜ SecurityContext๋ฅผ ์ €์žฅํ•œ๋‹ค (โžก Static ๋ณ€์ˆ˜ ์‚ฌ์šฉ)

SecurityContextHolder ์†Œ์Šค์ฝ”๋“œ. ๊ทธ๋Ÿด์ผ์€ ๊ฑฐ์˜ ์—†๊ฒ ์ง€๋งŒ ์ด๋ฅผ ์ปค์Šคํ…€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

MODE_INHERITABLETHREADLOCAL๋Š” ๋ถ€๋ชจ์Šค๋ ˆ๋“œ, ์ž์‹์Šค๋ ˆ๋“œ๋Š” ์•ˆ์จ๋ดค๋‹ค๋ฉด ์ƒ์†Œํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ

ํ•œ ์Šค๋ ˆ๋“œ(๋ถ€๋ชจ)์•ˆ์—์„œ ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ(์ž์‹)์„ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค. ThreadLocal์€ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ์ฃผ์–ด์ง€๋Š” ๋ฉ”๋ชจ๋ฆฌ์ด๋ฏ€๋กœ, ๋‹น์—ฐํžˆ ๋ณ„๋„์˜ ์„ค์ •์—†์ด๋Š” ๋ถ€๋ชจ์™€ ์ž์‹์˜ SecurityContext๊ฐ€ ๊ณต์œ ๋˜์ง€ ์•Š๋Š”๋‹ค.

@GetMapping("/home")
public String helloHome(){
	
    // ์ž์‹ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ
    new Thread(
    	new Runnable(){
            @Override
            public void run(){
            	// ์•„๋ž˜ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค๋ฅธ Context๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํ˜„์žฌ ์Šค๋ ˆ๋“œ์™€ ๊ณต์œ ๋˜์ง€ ์•Š๋Š”๋‹ค.
                // ์ฆ‰ ๋ฐฉ๊ธˆ ๋กœ๊ทธ์ธ์„ ํ•ด์„œ ์„ธ์…˜์— ์ €์žฅ๋˜์—ˆ์–ด๋„ ์—ฌ๊ธฐ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. 
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            }
        }
    ).start();
}

 

์ด๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๊ทธ๋ ค๋ณด๋ฉด, ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

์ฐธ๊ณ ๋กœ HttpSession์—์„œ๋Š” SPRING_SECURITY_CONTEXT ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ž์žฅ๋œ๋‹ค.

์œ„์—์„œ๋„ ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ, SecurityContextHolder์—์„œ ์•„๋ฌด๋Œ€์„œ๋‚˜ ์ธ์ฆ๊ฐœ์ฒด๋ฅผ ๊บผ๋‚ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

Authentication authentication = SecurityContextHolder.getContext().getAuthentication()

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ Security Context ์ €์žฅ์†Œ์ด๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์ด clear๋ฉ”์„œ๋“œ๋กœ ํ˜„์žฌ ์ปจํ…์ŠคํŠธ๋ฅผ ๋‚ ๋ ค๋ฒ„๋ฆด ์ˆ˜๋„ ์žˆ๋‹ค.

SecurityContextHolder.clearContext() // SecurityContext ๊ธฐ์กด ์ •๋ณด ์ดˆ๊ธฐํ™”

 

์ต๋ช… ์‚ฌ์šฉ์ž

  • ์ƒˆ๋กœ์šด SecurityContext๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Holder์— ์ €์žฅํ•œ๋‹ค.
  • AnonymousAuthentication-Filter์—์„œ AnonymousAuthentication-Token ๊ฐ์ฒด๋ฅผ SecurityContext์— ์ €์žฅํ•œ๋‹ค.

 

์ธ์ฆ ์‹œ

  • ์ƒˆ๋กœ์šด SecurityContext๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Holder์— ์ €์žฅํ•œ๋‹ค.
  • UsernamePasswordAuthenticationFilter์—์„œ ์ธ์ฆ ์„ฑ๊ณต ํ›„, S.C์— usernmaePasswordAuthentication์„ ์ €์žฅ
  • ์ธ์ฆ์ด ์ตœ์ข… ์™„๋ฃŒ๋˜๋ฉด S.C PesistenceFilter๊ฐ€ ์„ธ์…˜์— S.C๋ฅผ ์ €์žฅํ•œ๋‹ค. (SPRING_SECURITY_CONTEXT : S.C ๊ฐ์ฒด)

 

์ธ์ฆ ํ›„ 

  • ์„ธ์…˜์—์„œ S.C๋ฅผ ๊บผ๋‚ด์–ด Holder์— ์ €์žฅํ•œ๋‹ค.
  • S.C์•ˆ์—์„œ Authentication ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํŒ๋‹จํ•˜๊ณ , ์žˆ๋‹ค๋ฉด ์ธ์ฆ ๊ณผ์ •์—†์ด ์ธ์ฆ์„ ์œ ์ง€ํ•œ๋‹ค.

 

์ฐธ๊ณ ๋กœ MODE_GLOBAL ๋ชจ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, Http ์‘๋‹ต์ดํ›„์—๋Š” ํ•„์š”์—†์œผ๋ฏ€๋กœ Holder์—์„œ S.C๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

SecurityContextHolder.clearContext() // ์„ธ์…˜์—๋Š” ๋‚จ์•„์žˆ์Œ. ํ˜„์žฌ ์Šค๋ ˆ๋“œ ๋ฉ”๋ชจ๋ฆฌ ์‚ญ์ œ

๊ทธ๋ž˜์„œ ์‹ค์ œ ํ•„ํ„ฐ์ˆœ์„œ๋„ 2๋ฒˆ์งธ์— ์œ„์น˜๋˜์–ด์žˆ๋‹ค.

1๋ฒˆ ์ธ๋ฑ์Šค์— SecurityContextPesistenceFilter๊ฐ€ ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„ธ์…˜์—์„œ S.C๋ฅผ ๊บผ๋‚ด Holder์— ์ €์žฅํ•œ๋‹ค.
๋ณ„๊ฑฐ์—†๋‹ค. ํ˜„์žฌ ์„ธ์…˜์— S.C๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ ํ›„, ์žˆ๋‹ค๋ฉด ๊บผ๋‚ด๊ณ  ์—†๋‹ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ์ด๋™.

 

 

 

๐Ÿ“‘ ์ธ์ฆ(Authentication) Flow

  • ๋ชจ๋“  ์š”์ฒญ์€ Manager๋ฅผ ํ†ตํ•ด ์ง„ํ–‰๋œ๋‹ค. ํ•˜์ง€๋งŒ Manager๋Š” ์ผ์ข…์˜ ์ปจํŠธ๋กค๋Ÿฌ์ด๊ณ , ์‹ค์ œ ์ธ์ฆ์€ Provider์— ์œ„์ž„ํ•œ๋‹ค.
  • Provider๋Š” ์ธ์ฆ๊ณผ์ •์„ ๋‹ด๋‹นํ•˜๋ฉฐ, ์œ ์ € ๋ฐ์ดํ„ฐ ์กฐํšŒ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด UserDetailsService์— UserDeatils๊ฐ์ฒด๋ฅผ ์š”์ฒญํ•œ๋‹ค.
  • UserDetailsService๋Š” Repository์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ์„œ๋น„์Šค๊ฐ์ฒด์ด๋ฉฐ, User๋ฅผ UserDetails๋กœ ๊ฐ์‹ธ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ด๋ ‡๊ฒŒ Provider๊ฐ€ UserDetails๋ฅผ ๋ฐ›์•„ ์ธ์ฆ๊ณผ์ •์„ ๊ฑฐ์ณ, ์ธ์ฆ์— ์‹คํŒจํ•œ๋‹ค๋ฉด ์ ์ ˆํ•œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
  • ์ธ์ฆ์— ์„ฑ๊ณตํ•œ๋‹ค๋ฉด Provider๋Š” UserDetails์™€ ์ธ๊ฐ€์ •๋ณด(authorities)๋ฅผ ํ•œ ๊ฐ์ฒด Authentication์œผ๋กœ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•˜๊ณ 
  • ์ตœ์ข…์ ์œผ๋กœ Manager๊ฐ€ Filter์— Authentication๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด, ํ•„ํ„ฐ์—์„œ S.C์— ์ธ์ฆ ๊ฐ’์„ ์ตœ์ข…์ ์œผ๋กœ ์ €์žฅํ•œ๋‹ค.

์˜ˆ์™ธ ๋ฐœ์ƒ์‹œ Filter๋Š” ๋“ฑ๋ก๋œ FailHandler๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์ธ์ฆ์ด ์™„๋ฃŒ๋œ Autentication์€ ํ˜„์žฌ Holder์˜ S.C์— ์ €์žฅ๋˜๊ณ , S.C๋Š” ์„ธ์…˜์— ์ €์žฅ๋œ๋‹ค.

์ดํ›„ ์ƒˆ๋กœ์šด ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ, Holder๊ฐ€ S.C๋ฅผ ์„ธ์…˜์—์„œ ๊บผ๋‚ด์™€์„œ ์‚ฌ์šฉํ•˜๊ณ , ์‘๋‹ต์ดํ›„ S.C๋ฅผ clearํ•œ๋‹ค.

 

์ฆ‰ S.C๋Š” Http ์š”์ฒญ-์‘๋‹ต๊ณผ ๊ฐ™์€ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ ์„œ๋ฒ„์— ์žˆ๋Š” Holder๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๊ณ , ์ €์žฅํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ AuthenticationProvider์—์„œ ์œ ์ € ๊ฒ€์ฆ ์‹คํŒจ์‹œ, ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

 

 

๐Ÿ“‘ ์ธ์ฆ ๋งค๋‹ˆ์ € (AuthenticationManager)

๋งค๋‹ˆ์ €๋Š” ์ผ์ข…์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ผ๊ณ  ํ–ˆ๋‹ค. ์‹ค์ œ ๋™์ž‘์€ ProviderManager๋ฅผ ํ†ตํ•ด ์ง„ํ–‰๋œ๋‹ค.

provider๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด Form ์ธ์ฆ์š”์ฒญ์ด ๋“ค์–ด์™”๋‹ค๋ฉด, ์ด ์ธ์ฆ์ด ๊ฐ€๋Šฅํ•œ Provider๊ฐ์ฒด(Dao..Provider)๋ฅผ ์ฐพ์•„์„œ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์„ ํƒ๋œ Provider ๊ฐ์ฒด๊ฐ€ ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ๋งค๋‹ˆ์ €์—๊ฒŒ Authentication ๊ฐ์ฒด์—๊ฒŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ˜•์‹์ด๋‹ค.

ProviderManager๊ฐ€ ์ ์ ˆํ•œ Provider๋ฅผ ์ฐพ๋Š” ๊ณผ์ •

 

ProviderManager์—๋Š” parent ์†์„ฑ ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค. (*์ƒ์† ์•„๋‹˜)

์ด๋Š” ํ˜„์žฌ ProviderManager์— ์ฒ˜๋ฆฌ๊ฐ€๋Šฅํ•œ Provider๊ฐ€ ์—†๋‹ค๋ฉด, ํ•ด๋‹น parent๊ฐ’์— ์žˆ๋Š” ProvierManager์—๊ฒŒ ์š”์ฒญ์„ ํ•œ๋‹ค.

๋งˆ์น˜ ํŠธ๋ฆฌ ํƒ์ƒ‰์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌ๊ฐ€๋Šฅํ•œ Provider๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ์ง„ํ–‰ํ•œ๋‹ค. ๋ชป์ฐพ์•˜๋‹ค๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ, ๊ธฐ๋ณธ๊ฐ’์€ ๋ชจ๋“  provider๋ฅผ ํƒ์ƒ‰ํ•˜์ง€ ์•Š๋„๋ก ๋งŒ๋“ค์–ด์ ธ์žˆ๋‹ค.

AuthenticationManagerBuilder๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด parent๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด ๋ชจ๋“  Provider๋ฅผ ํƒ์ƒ‰ํ•˜๋„๋ก ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

 

 

 

๐Ÿ“‘ ์ธ์ฆ ์ฒ˜๋ฆฌ์ž (AuthenticationProvider)

Filter โžก Manager โžก Provider.support(~) ๋ฅผ ํ†ตํ•ด ์ ์ ˆํ•œ ๊ฐ์ฒด๋ฅผ ์ฐพ์•˜๋‹ค๋ฉด provider์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘๋œ๋‹ค.

ํŠน๋ณ„ํ•œ๊ฑด ์—†๊ณ , Provider๋Š” User๊ฐ์ฒด๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, UserDetails ๊ฐ์ฒด๋กœ ๋‹ค๋ฃจ๊ฒŒ ๋œ๋‹ค.

๋ชจ๋“  ๊ฒ€์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด Authentication ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์œ ์ €์ •๋ณด(Principal)์™€ ๊ถŒํ•œ์ •๋ณด๋ฅผ ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 

์ธ์ฆ ์„ฑ๊ณต์‹œ ์œ ์ €์ •๋ณด(pricipal), ๋น„๋ฐ€๋ฒˆํ˜ธ(credential), ๊ถŒํ•œ(authorities)์„ Authentication์— ๋‹ด๋Š”๋‹ค.
์ธ์ฆ ์„ฑ๊ณต์ดํ›„, S.C์— ์ธ์ฆ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  successHandler๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

 

๐Ÿ’ญ ์ธ๊ฐ€(Authorization)

์ธ์ฆ์ด ๋‚ด๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ด์—ˆ๋‹ค๋ฉด,

์ธ๊ฐ€๋Š” ๋ˆ„๊ตฌ์ธ์ง€ ํ™•์ธ์€ ํ–ˆ์œผ๋‚˜ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋Š” ํฌ๊ฒŒ 3๊ฐ€์ง€ ๊ณ„์ธต์œผ๋กœ Authorization์„ ์ œ๊ณตํ•ด์ค€๋‹ค.

  • ์›น ๊ณ„์ธต์€ ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” URL, ์ฆ‰ ํ™”๋ฉด ๋‹จ์œ„์˜ ๊ถŒํ•œ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
  • ์„œ๋น„์Šค ๊ณ„์ธต์€ AOP์™€ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ด์šฉํ•œ ๊ธฐ๋Šฅ ๋‹จ์œ„์˜ ๋ณด์•ˆ๊ธฐ๋Šฅ์ด๋‹ค. โžก ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ์— ๊ถŒํ•œ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋„๋ฉ”์ธ ๊ณ„์ธต์€ ๊ฐ์ฒด๋‹จ์œ„์˜ ๋ณด์•ˆ ๊ธฐ๋Šฅ์ด๋‹ค. โžก File, DB์— ์ ‘๊ทผ๊ถŒํ•œ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ธ๊ฐ€๋Š” ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ์ฒด์ธ์ค‘, ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ํ•„ํ„ฐ์ธ FilterSecurityInterceptor ํ•„ํ„ฐ์—์„œ ์ด๋ฃจ์–ด์ง„๋‹ค.

  • [์•ž์˜ ํ•„ํ„ฐ๋“ค์—์„œ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž]์— ๋Œ€ํ•˜์—ฌ ํŠน์ • ์š”์ฒญ์˜ ์Šน์ธ/๊ฑฐ๋ถ€ ์—ฌ๋ถ€๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ์ • 
     โžก ์ธ์ฆ ๊ฐ์ฒด ์—†์ด ๋ณดํ˜ธ์ž์›์— ์ ‘๊ทผ์„ ์‹œ๋„ํ•  ๊ฒฝ์šฐ AuthenticationException ์„ ๋ฐœ์ƒ
     โžก ์ธ์ฆ ํ›„ ์ž์›์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ถŒํ•œ์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ AccessDeniedException ์„ ๋ฐœ์ƒ
  • ๊ถŒํ•œ ์ œ์–ด ๋ฐฉ์‹ ์ค‘ HTTP ์ž์›์˜ ๋ณด์•ˆ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ
  • ๊ถŒํ•œ ์ฒ˜๋ฆฌ๋ฅผ AccessDecisionManager์—๊ฒŒ ๋งก๊น€

 

 

๐Ÿ“‘ FilterSecurityInterceptor ์˜ ๋™์ž‘

์•ž์—์„œ ์ธ์ฆ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค๋ฉด, SecurityMetadataSource ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ๊ถŒํ•œ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

์ฐธ๊ณ ๋กœ ์ธ์ฆ ๊ฐ์ฒด๊ฐ€ ์žˆ์œผ๋‚˜, ์ธ๊ฐ€(๊ถŒํ•œ)์ •๋ณด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ๋ณ„๋‹ค๋ฅธ ๋™์ž‘์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
๊ฐ€์ ธ์˜จ attributes์—๋Š” ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ๊ถŒํ•œ ์ •๋ณด๊ฐ’๋“ค์ด ๋“ค์–ด๊ฐ€์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  AccessDecisionManager์—๊ฒŒ ๊ถŒํ•œ์ •๋ณด๋ฅผ ์ฃผ๊ฒŒ๋˜๋ฉด, ํ˜„์žฌ ์ธ์ฆ๊ฐœ์ฒด๊ฐ€ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.

 

 

๋ฌผ๋ก  ์ธ์ฆ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๋งค๋‹ˆ์ €๋Š” ์ปจํŠธ๋กค๋Ÿฌ ์—ญํ• ์ด๋ฉฐ, ์‹ค์ œ ์ธ๊ฐ€๋Š” AccessDecisionVoter ๊ฐ์ฒด๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค.

์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋˜๋ฉด FilterSecurityInterceptor๋ฅผ ํ˜ธ์ถœํ•œ ExceptionTranslationFilter์— ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

ํ•„ํ„ฐ ์ด๋ฆ„์ด ์ธํ„ฐ์…‰ํ„ฐ์ธ ์ด์œ ๋Š”, ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ExceptionTranslationFilter๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

 

๐Ÿ“‘ ์ธ๊ฐ€๋งค๋‹ˆ์ € (AccessDecisionManager)

ํ•˜๋‚˜์˜ ๋งค๋‹ˆ์ €๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ Voter ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ธ๊ฐ€(์ ‘๊ทผํ—ˆ์šฉ, ๊ฑฐ๋ถ€, ๋ณด๋ฅ˜)์— ํ•ด๋‹นํ•˜๋Š” ๋ฆฌํ„ด ๊ฐ’์„ ๋ฐ›๊ณ  ์ตœ์ข… ํŒ๋‹จํ•จ.

 

 

๐Ÿ“‘ AccessDecisionVoter

์•„๋ž˜์˜ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ถŒํ•œ์„ ํŒ๋‹จํ•˜๋ฉฐ, ์ƒ์ˆ˜๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ (์ ‘๊ทผํ—ˆ์šฉ1, ์ ‘๊ทผ๊ฑฐ๋ถ€0, ์ ‘๊ทผ๋ณด๋ฅ˜-1)

  • Authentication ์ธ์ฆ ์ •๋ณด( user )
  • FilterInvocatior ์š”์ฒญ ์ •๋ณด( antMatcher("/user") )
  • ConfigAttributes ๊ถŒํ•œ ์ •๋ณด ( hasRole("USER") )

์ฐธ๊ณ ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒ์ˆ˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ.

  • ACCESS_GRANTED (1) ์Šน์ธ
  • ACCESS_DENIED (0) ๊ฑฐ์ ˆ
  • ACCESS_ABSTAIN (-1) ๋ณด๋ฅ˜
    ๋ณด๋ฅ˜๋Š” ํ•ด๋‹น Voter๊ฐ€ ํŒ๋‹จ์„ ๋‚ด๋ฆด ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•จ 

antMatcher(String antPattern)// HttpSecurity์ œ๊ณต๋œ ant ํŒจํ„ด๊ณผ ์ผ์น˜ํ•  ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mvcMatcher(String mvcPattern)// HttpSecurity์ œ๊ณต๋œ Spring MVC ํŒจํ„ด๊ณผ ์ผ์น˜ํ•  ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MVC Matcher(์Šคํ”„๋ง 4.1.1)๋Š” SpringMVC์˜ HandlerMappingIntrosepctor๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. a

Ant Matcher(์Šคํ”„๋ง 3.1)๋Š” ์•„ํŒŒ์น˜์˜ Ant ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Ant ์˜›๋‚  ๋นŒ๋“œ๋„๊ตฌ์ด๊ณ , bulid.xml์— ์‚ฌ์šฉ๋˜๋Š” ๋ฌธ๋ฒ•์ž…๋‹ˆ๋‹ค.
์œ„ ๋‘๊ฐœ์˜ Matcher๋Š” RequestMatcher ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ผ๋ฐ˜์ ์œผ๋กœ Mvc Matcher๊ฐ€ ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. API ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด Mvc Matcher๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

antMatchers("/secured") // ํ•ด๋‹น URL๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

mvcMatchers("/secured") // /secured, /secured/ /secured.html /secured.xyz...๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค
// ์ด๋Š” ์Šคํ”„๋ง MVC์˜ @RequestMapping(....)๊ณผ ๊ฐ™์€ URL ๊ทœ์น™์ž…๋‹ˆ๋‹ค.
antMatcher("/users/**") //matches any path starting with /users
antMatchers("/users") //matches only the exact /users URL
mvcMatchers("/users") //matches /users, /users/, /users.html

public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
  .authorizeRequests()
  .antMatchers("/users/movie/**") // matches any path starting with /users/movie
  .hasRole("ADMIN") ...
  }
}

๐Ÿ’ญ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์•„ํ‚คํ…์ฒ˜ ์ •๋ฆฌ

์ฒ˜๋ฆฌํ•  ๋‚ด์šฉ์ด ์—†์œผ๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ๋„˜์–ด๊ฐ„๋‹ค. (chain.doFilter)

๋งˆ์ง€๋ง‰ FilterSecurityInterceptor์—์„œ ๊ถŒํ•œ(์ธ๊ฐ€)๊นŒ์ง€ ์˜ˆ์™ธ์—†์ด ์™„๋ฃŒ๋˜๋ฉด ์ •์ƒ์ ์ธ ์ ‘๊ทผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ