# [Security] Jwt Authorization ๊ตฌํ˜„ by Overriding Spring Security ์ธ์ฆ ์•„ํ‚คํ…์ณ
Study Repository

[Security] Jwt Authorization ๊ตฌํ˜„ by Overriding Spring Security ์ธ์ฆ ์•„ํ‚คํ…์ณ

by rlaehddnd0422

์ง€๋‚œ ํฌ์ŠคํŒ…์— ์ด์–ด Spring Security์— ํ•„ํ„ฐ๋ฅผ ์ปค์Šคํ…€ํ•˜์—ฌ Authorization Filter๋ฅผ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค.

 

๋กœ๊ทธ์ธ์— Jwt ๋ฐฉ์‹์„ ์ ์šฉํ•  ๋•Œ, Authentication Filter์—์„œ๋Š” ์š”์ฒญํ—ค๋”๋ฅผ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ํ† ํฐ์œผ๋กœ ๋ณ€ํ™˜์‹œํ‚ค๊ณ .. authenticate()๋ฅผ ํ†ตํ•ด ํ† ํฐ๊ณผ DB์˜ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋น„๊ตํ•˜์—ฌ ๊ฒ€์ฆํ•˜๊ณ .. ํ† ํฐ์„ ๋งŒ๋“ค์–ด ์‘๋‹ตํ—ค๋”์— ์„ค์ •ํ•˜๊ณ .. ๋“ฑ ๊ฝค ๋ณต์žกํ•œ ๊ณผ์ •์„ ๊ฑฐ์ณ ์ธ์ฆ์ด ์ด๋ฃจ์–ด์กŒ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ, Authorization์˜ ๊ณผ์ •์€ ๋น„๊ต์  ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค!

 

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์ œํ•œ๋œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ Authentication ๊ณผ์ •์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ JWT๋ฅผ ์š”์ฒญํ—ค๋”์— ๋ณด๋‚ด๊ณ ,

์„œ๋ฒ„์—์„œ๋Š” ์ด ํ† ํฐ์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌ ํ›„ ์œ ํšจํ•˜๋ฉด ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ ํ•„์š”ํ•œ ํ•„ํ„ฐ๋Š” ๋ฐ”๋กœ 'BasicAuthenticationFilter' ์ž…๋‹ˆ๋‹ค.

 

BasicAuthenticationFilter

์ด ํ•„ํ„ฐ๋Š” Authorization, Authentication์ด ํ•„์š”ํ•œ ํŠน์ • ์ฃผ์†Œ๋ฅผ ์š”์ฒญํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํ•„ํ„ฐ์ž…๋‹ˆ๋‹ค.

 

์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋กœ๊ทธ์ธ(์ธ์ฆ)์—๋งŒ ์‚ฌ์šฉ๋˜์—ˆ๋˜ UsernamePasswordAuthenticationFilter๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด ํ•„ํ„ฐ๋ฅผ ์ƒ์†๋ฐ›์•„ JWT ๋ฐฉ์‹์— ๋งž๊ฒŒ ๋ฆฌํŽ™ํ† ๋งํ•˜๊ณ  ๋“ฑ๋กํ•ด๋ด…์‹œ๋‹ค.

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
}
BasicAuthentication ํ•„ํ„ฐ๋Š” AuthenticationManager๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž์— ๋ฐ˜๋“œ์‹œ ๋„ฃ์–ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

public JwtAuthorizationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
    super(authenticationManager, authenticationEntryPoint);
}

+ ์ถ”๊ฐ€์ ์œผ๋กœ ์—ฌ๊ธฐ์—์„œ AuthenticationEntryPoint๋Š” ์ธ์ฆ ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ํ•ธ๋“ค๋Ÿฌ์ž…๋‹ˆ๋‹ค. 

์ง€๊ธˆ ๋‹น์žฅ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋Š” ์šฐ์„ ์ ์ด์ง€๋Š” ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ฒซ ๋ฒˆ์งธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 


BasicAuthenticationFilter - doFilterInternal()

์ผ๋ฐ˜์ ์ธ ํ•„ํ„ฐ์˜ doFilter์˜ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ, ์‹ค์งˆ์ ์œผ๋กœ ์ด ๋ฉ”์†Œ๋“œ์— ๊ถŒํ•œ, ์ธ์ฆ์— ๋Œ€ํ•œ ๊ฒ€์ฆ๋กœ์ง์ด ๊ตฌํ˜„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    String jwtHeader = request.getHeader("Authorization");

    // ํ—ค๋”๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
    if (jwtHeader == null || !jwtHeader.startsWith("Bearer")) {
        chain.doFilter(request, response);
        return;
    }

    String jwtToken = request.getHeader("Authorization").replace("Bearer ","");
    String username = JWT.require(Algorithm.HMAC512("cos")).build().verify(jwtToken).getClaim("username").asString();

    // ์„œ๋ช…์ด ์ •์ƒ์ ์œผ๋กœ ๋จ
    if (username != null) {
        Optional<User> userEntity = userRepository.findByUsername(username);
        PrincipalDetails principalDetails = new PrincipalDetails(userEntity.get());
        log.info("HI");
        // Jwt ํ† ํฐ ์„œ๋ช…์„ ํ†ตํ•ด ์„œ๋ช…์ด ์ •์ƒ์ด๋ฉด Authentication ๊ฐ์ฒด ์ƒ์„ฑ
        Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());

        log.info("{}", authentication.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }
    super.doFilterInternal(request, response, chain);
}

๋กœ์ง์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค.

1. ์šฐ์„  Request Header์— Authorization์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ( ๋กœ๊ทธ์ธ ๊ณผ์ •์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ JWT )

2. ์—†๋‹ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ๋„˜๊ธฐ๊ณ  ๋ฆฌํ„ด.

3. ์žˆ๋‹ค๋ฉด ๋ฐœ๊ธ‰๋ฐ›์€ ํ† ํฐ์˜ ๋ฒ ๋ฆฌ์–ด๋ฅผ ๋ฒ—๊ธฐ๊ณ , ์ˆœ์ˆ˜ Jwt ๋งŒ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build();
String username = jwtVerifier.verify(jwtToken).getClaim("username").asString();
  • 4. JWT์˜ require ๋ฉ”์†Œ๋“œ๋กœ ํ† ํฐ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์‹œํฌ๋ฆฟ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ํ† ํฐ ํ•ด๋… ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • ํ† ํฐ ํ•ด๋…๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์š”์ฒญ ํ—ค๋”๋กœ ๋ฐ›์€ ํ† ํฐ์„ ํ•ด๋…ํ•˜์—ฌ username์˜ ํ•„๋“œ๊ฐ’์„ string์œผ๋กœ ๋ณ€ํ™˜
    • username์ด null์ด ์•„๋‹ˆ๋ผ๋ฉด ์„œ๋ช…์ด ์ •์ƒ์ ์œผ๋กœ ๋˜์—ˆ๋‹ค๊ณ  ๋ด๋„ ๋ฌด๋ฐฉ.
// ์„œ๋ช…์ด ์ •์ƒ์ ์œผ๋กœ ๋จ
if (username != null) {
    Optional<User> userEntity = userRepository.findByUsername(username);
    PrincipalDetails principalDetails = new PrincipalDetails(userEntity.get());
    
    // Jwt ํ† ํฐ ์„œ๋ช…์„ ํ†ตํ•ด ์„œ๋ช…์ด ์ •์ƒ์ด๋ฉด Authentication ๊ฐ์ฒด ์ƒ์„ฑ
    Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());

    SecurityContextHolder.getContext().setAuthentication(authentication);
    chain.doFilter(request, response);
}
  • ์„œ๋ช…(์ธ์ฆ)์€ ํ†ต๊ณผํ–ˆ์œผ๋‹ˆ ์ด์ œ ์ธ๊ฐ€๋งŒ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • jwt๋ฅผ ํ•ด๋…ํ•˜์—ฌ ์–ป์€ username์„ ์ฐพ๊ณ , ์ฐพ์€ user๋ฅผ PrincipalDetails์— ๋‹ด์•„ Authentication ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ค์‹œ๋‹ค.
    • ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋งŒ๋“  Authentication ๊ฐ์ฒด๋ฅผ SecurityContext์— ๋‹ด์•„์ฃผ๊ณ  ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ์ง„ํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.
  • Authentication ๊ฐ์ฒด๋ฅผ Security Context์— ๋‹ด์•„์„œ, Authorization์„ ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.
    • ์„œ๋ฒ„์—์„œ๋Š” Security Context์— ๋‹ด๊ธด Authentication ๊ฐ์ฒด ๋‚ด๋ถ€์˜ UserDetails ๊ฐ์ฒด์˜ Role ์ •๋ณด๋ฅผ ํ™•์ธํ•˜์—ฌ ์š”์ฒญ์„ ํ—ˆ์šฉํ• ์ง€, ๊ฑฐ๋ถ€ํ• ์ง€ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.

 

ํ•„ํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋ชจ๋‘ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. SecurityConfig์˜ ํ•„ํ„ฐ์— ๋“ฑ๋กํ•ด์ฃผ๊ณ  Postman์œผ๋กœ ํ…Œ์ŠคํŠธํ•ด๋ด…์‹œ๋‹ค.

 

ํ•„ํ„ฐ Override

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig{

    private final CorsFilter corsFilter;
    private final UserRepository userRepository;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // ์„ธ์…˜ ์‚ฌ์šฉ X, Stateless
                .and()
                .formLogin().disable() // ํผ ๋กœ๊ทธ์ธ ์‚ฌ์šฉ X
                .httpBasic().disable() // ๊ธฐ๋ณธ์ธ์ฆ๋ฐฉ์‹ ID, PW ์‚ฌ์šฉ X
                .apply(new MyCustomDsl())
                .and()
                .authorizeRequests()
                .antMatchers("/api/v1/user/**")
                .access("hasRole('ROLE_USER') or hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/manager/**")
                .access("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/api/v1/admin/**")
                .access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll();

        return http.build();
    }

    public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
            http
                    .addFilter(corsFilter)
                    .addFilter(new JwtAuthenticationFilter(authenticationManager))// ์ธ๊ฐ€
                    .addFilter(new JwtAuthorizationFilter(authenticationManager,userRepository)); // ์ธ์ฆ
        }
    }

Postman ๊ฒ€์ฆ

Login์„ ํ†ตํ•ด JWT ๋ฐœ๊ธ‰

 

 

JWT๋ฅผ ์š”์ฒญ ํ—ค๋”์— ๋„ฃ์–ด์„œ ์ œํ•œ๋œ ๋ฆฌ์†Œ์Šค ์š”์ฒญ

user Page ์‘๋‹ต Ok

 

admin Page ์š”์ฒญ ์‹œ ์˜ค๋ฅ˜ ํŽ˜์ด์ง€ ์‘๋‹ต

 

๊ถŒํ•œ ๋ณ€๊ฒฝ ํ›„ admin ํŽ˜์ด์ง€ ์š”์ฒญ Test

admin page ์š”์ฒญ ์‘๋‹ต ok


<์ •๋ฆฌ>

  • ๋กœ๊ทธ์ธ์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ JWT๋ฅผ ์‚ฌ์šฉํ•ด์„œ,  ์ธ์ฆ, ์ธ๊ฐ€๊ฐ€ ํ•„์š”ํ•œ ์ œํ•œ๋œ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ ์š”์ฒญ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ํ•„ํ„ฐ๋ฅผ JWT ์ธ์ฆ ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŽ™ํ† ๋งํ•˜์—ฌ ์ ์šฉํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
  • BasicAuthenticationFilter๋Š” ์ธ์ฆ, ์ธ๊ฐ€๊ฐ€ ํ•„์š”ํ•œ ์ œํ•œ๋œ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ ์š”์ฒญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•„ํ„ฐ์ž…๋‹ˆ๋‹ค.
  • Spring Security์˜ ์ „์ฒด์ ์ธ ์ธ์ฆ ์•„ํ‚คํ…์ฒ˜์˜ ํ๋ฆ„์„ ์ดํ•ดํ•˜๋ฉด, Jwt Base์˜ Authentication, Authorization์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง๋“ค์„ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

<์ฐธ๊ณ  ์ž๋ฃŒ>

https://www.youtube.com/watch?v=mW-8MQ-4arU 

 

 

[Spring Boot] ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ JWT ์‚ฌ์šฉํ•˜๊ธฐ

JWT๋ž€? [๋ธ”๋กœ๊ทธ ๋งํฌ ์˜ˆ์ •] ์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ ๋กœ๊ทธ์ธ์„ ํ•˜์˜€์„ ๋•Œ Access Token์„ ๋ฐœ๊ธ‰ํ•ด์ฃผ๋Š” ๊ฒƒ๊ณผ ์‚ฌ์šฉ์ž๊ฐ€ ํ—ค๋”์— ํ† ํฐ์„ ๋‹ด์•„ ๋ณด๋ƒˆ์„ ๋•Œ ์ ‘๊ทผ๊ฐ€๋Šฅํ•œ ์‚ฌ์šฉ์ž์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ์ฒดํฌํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด

devlog-wjdrbs96.tistory.com

 

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

Study Repository

rlaehddnd0422

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