๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“• Spring Framework/Spring ๊ฐœ๋… ์ •๋ฆฌ

Spring Security [1] - JWT๋ฅผ ์ด์šฉํ•œ REST API ์ธ์ฆ๊ณผ ์ธ๊ฐ€

by GroovyArea 2022. 8. 18.
๊ธฐ์กด ์ธ์ฆ์€ JWT๋ฅผ ์ด์šฉํ•œ ํ•„ํ„ฐ๋กœ, ์ธ๊ฐ€๋Š” ์ธํ„ฐ์…‰ํ„ฐ๋กœ ์• ๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•ด ์†์ˆ˜ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค.

์ด๋ฒˆ์— ๋ฆฌํŒฉํ„ฐ๋ง์„ ํ•˜๋ฉด์„œ, ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๋ณด์•ˆ ๊ด€๋ จ ํ”„๋ ˆ์ž„์›Œํฌ์ธ ์„œํ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž๋Š” ๊ฒฐ์ •์„ ๋‚ด๋ ค ๋„์ž…ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

์–ด๋ ต๋‹ค๊ณ ๋Š” ์–ผํ• ๋“ค์—ˆ์ง€๋งŒ, ์ด๋ ‡๊ฒŒ ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ค„ ๋ชฐ๋ž๋‹ค. ์—ฌ๋Ÿฌ ๋ธ”๋กœ๊ทธ๋“ค์„ ์ฐธ์กฐํ•˜๊ณ , ์ž˜ ์ฝํžˆ์ง€๋„ ์•Š๋Š” ๊ณต์‹๋ฌธ์„œ๋“ค์„ ๋ณด์•„๋„ ๋„๋ฌด์ง€ ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•˜๋‹ค.
์ผ๋‹จ ๋จธ๋ฆฟ์†์— ๊ทธ๋ ค์ ธ์•ผ ๊ฐ์ด ์žกํžˆ๋Š”๋ฐ, ์ด๊ฑด ๋ญ ํ•„ํ„ฐ๋„ ์—ฌ๋Ÿฌ ๊ฐœ์ด๋ฉฐ ๊ตฌํ˜„์ฒด๋„ ์™œ ์ด๋ ‡๊ฒŒ ๋งŽ์€์ง€ ๊ทธ์— ๋งž๋Š” ์ฑ…์ž„๊ณผ ์—ญํ• ์ด ๋„์ €ํžˆ ๊ฐ์ด ์˜ค์ง€ ์•Š๋Š”๋‹ค. 

์ „๋ถ€ ์ถ”์ƒํ™” ๋˜์–ด ์žˆ์–ด ์ปค์Šคํ…€ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ํŽธํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค๋Š”๋ฐ, ์ „๋ฐ˜์ ์œผ๋กœ ๋ชจ๋“  ๋‚ด์šฉ์„ ์ดํ•ดํ•˜๊ธฐ์—” ์‰ฝ์ง€ ์•Š๊ธฐ๋„ ํ•˜๊ณ  ๋”ฐ๋กœ ๊ณต๋ถ€๊ฐ€ ํ•„์š”ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๊ฑฐ์ง„ 1์ฃผ ๋ฐ˜์ด ๋„˜์–ด์„œ์•ผ ๋‚ด๊ฐ€ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋Š” ์ธ์ฆ ๋ฐฉ์‹์„ ์ ์šฉํ• ๋งŒํ•œ ๊ฐœ๋…์€ ์ดํ•ด๊ฐ€ ๊ฐ€ ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, ๊ถŒํ•œ ์ฒ˜๋ฆฌ๊นŒ์ง€๋Š” ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋งž๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ธ์ง€, ํด๋ฆฐ ํ•œ ์ฝ”๋“œ๊ฐ€ ์•„๋‹ ํ…Œ์ง€๋งŒ ๊ทธ ํ—˜๋‚œํ•œ ๊ณผ์ •์„ ์ •๋ฆฌํ•ด๋ณด๊ฒ ๋‹ค.

์ฐธ๊ณ ๋กœ ์ €๋Š” Access Token ํ•˜๋‚˜๋งŒ ๋ฐœ๊ธ‰ํ•ด ์ง„ํ–‰ํ–ˆ๋‹ต๋‹ˆ๋‹ค~

์Šคํ”„๋ง ์„œํ๋ฆฌํ‹ฐ๋ž€

  • ์Šคํ”„๋ง ๊ธฐ๋ฐ˜์˜ Authentication(์ธ์ฆ), Authorization(๊ถŒํ•œ)์„ ๋‹ด๋‹นํ•˜๋Š” ํ•˜์œ„ ํ”„๋ ˆ์ž„์›Œํฌ
  • ํ•„ํ„ฐ ๊ธฐ๋ฐ˜์˜ ๋™์ž‘

  • ์Šคํ”„๋ง ์„œํ๋ฆฌํ‹ฐ์˜ ํ•„ํ„ฐ ์ฒด์ธ ์ˆœ์„œ์ด๋‹ค. ์ฒ˜์Œ์—” ๋ณ„๋กœ ๊ณต๋“ค์—ฌ ๋ณด์ง„ ์•Š์•˜์ง€๋งŒ, ์–ด๋Š์ •๋„ ๋ณธ์ธ์ด ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์€ ๋ฐฉ์‹์˜ ํ•„ํ„ฐ๋ฅผ ์•Œ์•„๋ณด๊ณ  ์ˆœ์„œ๋ฅผ ๋ด ๋‘๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค..
  • ๋“ฑ๋กํ•œ ์š”์ฒญ์ด ์˜ค๋ฉด ์ด๋Ÿฐ์‹์˜ ํ•„ํ„ฐ ์ฒด์ด๋‹์„ ๊ฑฐ์ณ ๋””์Šค ํŒจ์ณ ์„œ๋ธ”๋ฆฟ์— ๋„์ฐฉํ•œ๋‹ค.

 

์Šคํ”„๋ง ์„œํ๋ฆฌํ‹ฐ ์„ค์ •

์ด ๊ธ€์€ ์ˆœ์ „ํžˆ Jwt Token์„ ์ด์šฉํ•œ ์ธ์ฆ, ์ธ๊ฐ€์˜ Rest Api๋ฅผ ์œ„์ฃผ๋กœ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฐฉ์‹์„ ์œ„์ฃผ๋กœ ์„ค์ •ํ•ด๋ณธ๋‹ค.

 

1. cofigure(WebSecurity web)

@Override
public void configure(WebSecurity web) {
    web.ignoring().antMatchers("/db/**",
            "/mapper/**",
            "/static/**",
            "/templates/**"
            ); // ํ…Œ์ŠคํŠธ ์‹œ path ์ˆ˜์ •ํ•  ๊ฒƒ.
}

=> ์„œํ๋ฆฌํ‹ฐ ํ•„ํ„ฐ ์ฒด์ธ์„ ๋ฌด์‹œํ•˜๋Š” url์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์›ฌ๋งŒํ•˜๋ฉด /resources ํŒจ์Šค๋ฅผ ์„ค์ •

 

2. configure(HttpSecurity http)

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilter(corsConfig.corsFilter())
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .httpBasic().disable()

                .authorizeRequests()
                .antMatchers("/login, /logout").permitAll()
                .antMatchers("/api/v1/**").hasAnyRole("USER", "ADMIN")
                .antMatchers("/api/v2/**").hasRole("ADMIN")// ํ…Œ์ŠคํŠธ ์‹œ path ๊ด€๋ฆฌํ•  ๊ฒƒ

                .and()
                .formLogin()
                .loginProcessingUrl("/login")


                .and()
                .logout()
                .logoutUrl("/logout")
                .addLogoutHandler((request, response, authentication) -> {
                    String token =
                            jwtProvider.getResolvedToken(request, JwtProvider.TOKEN_HEADER_KEY);

                    redisService.deleteData(token);
                })
                .logoutSuccessHandler((request, response, authentication) -> response.getWriter().write("Logout succeed"))

                .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtProvider, redisService))
                .addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtProvider, jwtValidator, jwtAuthenticator, redisService))

/*                .exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                .accessDeniedHandler(new CustomAccessDeniedHandler())*/;
    }

=> ์ž... ์ด๊ฒŒ ๋„๋Œ€์ฒด ๋ฌด์Šจ ๋ฉ”์„œ๋“œ ์ฒด์ธ์ด๋‹ค๋ƒ..

์ฒ˜์Œ ๋ดค์„ ๋• ๋ญ ์ด๋Ÿฐ๊ฒŒ ๋‹ค ์žˆ์–ด๋ผ๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋‹ค. ๊ฑฑ์ • ๋ง์ž,, ๊ณ„์† ์ฐพ์•„๋ณด๋‹ค ๋ณด๋ฉด ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๊ฑฐ๊ตฌ๋‚˜ ํ•˜๊ณ  ์„ค์ •ํ•˜๊ฒŒ ๋œ๋‹ค.. ใ…Žใ…Ž

๊ธฐ๋ณธ์ ์œผ๋กœ rest api ์ด๋ฏ€๋กœ, crsf(), httpBasic() ์€ disable() ์„ค์ •์„ ํ–ˆ๋‹ค.

๋˜ jwt ์ธ์ฆ ๊ธฐ๋ฐ˜์ด๋ฏ€๋กœ ์„ธ์…˜ ์ธ์ฆ์€ ๊บผ๋‘์—ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ , authorizeRequests() ๋ฉ”์„œ๋“œ๋กœ ๊ถŒํ•œ์„ ํ—ˆ์šฉํ•˜๋Š” ํŒจ์Šค๋“ค์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. 

์ € hasRole() ์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋“ค์€ access()๋ฅผ ๋Œ€์‹  ์ด์šฉํ•ด ํ‘œํ˜„์‹์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ๋„ ๋ฐ›๋Š”๋ฐ, ๊ทธ๋Ÿด ๊ฒฝ์šฐ์— ๊ฐ€๋…์„ฑ์ด ์•ˆ ์ข‹์•„ ๊ทธ๋ƒฅ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ–ˆ๋‹ค.

 

๋กœ๊ทธ์ธ๊ณผ, ๋กœ๊ทธ์•„์›ƒ์— ํ•ด๋‹น๋˜๋Š” ์„ค์ •์„ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋‚˜๋Š” ์ธ์ฆ ๊ด€๋ จ ์ž‘์—…์€ ์ „๋ถ€ ํ•„ํ„ฐ์—์„œ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด๋ฏ€๋กœ, ์š”์ฒญ url์„ ์„ค์ •ํ•˜๊ณ  ํ•„ํ„ฐ์—์„œ ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด ์ ์ ˆํžˆ login()์„ ์ž˜ ์ฒด์ด๋‹ ํ–ˆ๋‹ค. 

 

๋กœ๊ทธ์•„์›ƒ ๊ด€๋ จ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. logout()์„ ์ด์šฉํ•ด ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋“ค์„ ์ž˜ ์ฒด์ด๋‹ ํ•ด ๋žŒ๋‹ค์‹์œผ๋กœ ๊ฐ„๋‹จํžˆ ์•ก์…˜์„ ์ปค์Šคํ…€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋‹ค์‹œ ํ•œ๋ฒˆ ๋งํ•˜์ง€๋งŒ, ์„œํ๋ฆฌํ‹ฐ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋””ํดํŠธ ๋™์ž‘์ด ์žˆ๋Š”๋ฐ, ๋ณธ์ธ์ด ์›ํ•˜๋Š” ๋ฐฉ์‹์˜ ์ธ์ฆ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ฐ˜๋“œ์‹œ ์ƒ์†๋ฐ›์•„ ์ปค์Šคํ…€ํ•ด์ฃผ๊ณ , Bean์œผ๋กœ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ํ•ด์•ผ ํ•œ๋‹ค.

@Bean
public AuthenticationProvider authenticationProvider() {
    return new CustomAuthenticationProvider(userRepository, principalDetailService);
}

=> ์š” ๋†ˆ์ฒ˜๋Ÿผ~

๋‚˜๋งŒ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ๋ฐฉ์‹์ด ์žˆ์–ด ๊ทธ๊ฑธ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ปค์Šคํ…€ํ–ˆ๋‹ค.

 

๋Œ€๋žต์ ์ธ ํ”Œ๋กœ์šฐ

์ด ํ”Œ๋กœ์šฐ๋ฅผ ์ดํ•ดํ•˜๋Š”๊ฒŒ ํ•ต์‹ฌ์ด๋‹ค..!!

=> ์ฒ˜์Œ ๋ณด๋ฉด ๊ฐ์ด ์ž˜ ์•ˆ ์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค. ๊ณ„์† ๋ณด๊ณ  ์ฝ”๋“œ์— ์ ์šฉ์‹œํ‚ค๊ณ  ์‹คํ–‰ํ•ด๋ณด๋ฉด ๋จธ๋ฆฌ์— ์ž๋ฆฌ ์žกํžŒ๋‹ค.

ํ”Œ๋กœ์šฐ๋ฅผ ๊ทธ๋ ค๋ณด๋ฉด์„œ ๋ณต๊ธฐํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ• ๊ฐ™๋‹ค.

 

  1. ์š”์•ฝํ•˜์ž๋ฉด, ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์ธ์ฆ ํ•„ํ„ฐ์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ์šฉ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค. (UsernamePasswordAuthenticationToken)
  2. AuthenticatioManager๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๊ตฌํ˜„์ฒด์ธ ProvideManager๊ฐ€ ๋””ํดํŠธ ์ธ์ฆ ๋ฐฉ์‹์„ ํ†ตํ•ด ํ† ํฐ์„ ์ด์šฉํ•˜์—ฌ ์ธ์ฆํ•œ๋‹ค. ๊ทธ ๊ณผ์ •์—์„œ ํ•„์š”ํ•œ ๊ฒƒ์ด UserDetails ๊ฐ์ฒด์ธ๋ฐ ์ด ๊ฒƒ๋„ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค! (๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด ๊ตฌํ˜„ํ•˜๋ผ๋Š” ๋œป์ด๊ฒ ์ฃ ? ใ…Žใ…Ž)
  3. UserDetailService ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” loadByUsername(String username)์ด๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š”๋ฐ ๋‹น์—ฐํžˆ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์„œ DB์—์„œ ์œ ์ €๋ฅผ ๊ฐ€์ ธ์™€ UserDetials๋ฅผ ๊ณ„์Šนํ•œ ๊ฐ์ฒด ๋†ˆ์—๋‹ค๊ฐ€ ๋งคํ•‘ํ•ด ๋ฆฌํ„ด ์‹œํ‚ด ๋œ๋‹ค~ (๋ƒ๋Š” MapStruct ์ด์šฉ)
  4. ๊ทธ ํ›„ ๊ฐ์ž์˜ ๋ฐฉ์‹์— ๋งž๋Š” ์ธ์ฆ๊ณผ ์ธ๊ฐ€ ํ•„ํ„ฐ๋ฅผ ๊ณจ๋ผ ๊ตฌํ˜„ํ•˜๊ณ  ์ธ์ฆ์ด ์™„๋ฃŒ๋œ ๊ฐ์ฒด๋ฅผ SecurityContextHolder๋ผ๋Š” ๊ณณ์—๋‹ค๊ฐ€ ์ €์žฅ์‹œํ‚ค๋ฉด๋œ๋‹ค. ๊ทธ๋Ÿผ ํ•„์š”ํ•œ ๊ณณ์—์„œ ์ „์—ญ์ ์œผ๋กœ ์ €์žฅํ•œ authentication ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ด๊ณณ์„ ์ฐธ์กฐํ•˜๊ธธ ๋ฐ”๋ž€๋‹ค. (์•„์ฃผ ์„ค๋ช…์ด ์ข‹์Œ) https://catsbi.oopy.io/f9 b0 d83 c-4775-47da-9c81-2261851 fe0d0
 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ฃผ์š” ์•„ํ‚คํ…์ฒ˜ ์ดํ•ด

๋ชฉ์ฐจ

catsbi.oopy.io

 

์ฝ”๋“œ๋ฅผ ๋ด…์‹œ๋‹ค

JwtAuthenticationFilter.java - ๋กœ๊ทธ์ธ

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final JwtProvider jwtProvider;
    private final RedisService redisService;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtProvider jwtProvider, RedisService redisService) {
        super(authenticationManager);
        this.jwtProvider = jwtProvider;
        this.redisService = redisService;
        setFilterProcessesUrl("/login");

    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        try {
            LoginRequestDto loginRequestDto = new ObjectMapper()
                    .readValue(request.getInputStream(), LoginRequestDto.class);

            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                    loginRequestDto.getLoginId(), loginRequestDto.getPassword(), new ArrayList<>()
            );

            return getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();

        String token = jwtProvider.createToken(String.valueOf(principalDetails.getId()), principalDetails.getLoginId(), principalDetails.getRole());

        redisService.setDataExpire(principalDetails.getLoginId(), token, JwtProvider.getEXPIRED_TIME());

        response.addHeader(JwtProperties.TOKEN_HEADER_KEY.getKey(), JwtProperties.AUTH_TYPE.getKey() + token);
    }
}
  • /login ์š”์ฒญ์— ํ•œํ•ด ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์นœ๋‹ค. setFilterProcessesUrl() ์ด์šฉ
  • attempAuthentication()์„ Override ํ•ด์„œ ์ธ์ฆ์„ ์‹œ๋„ํ•  ํ† ํฐ์„ ์ƒ์„ฑ ํ›„  authenticationManager๋ฅผ ํ†ตํ•ด ์ธ์ฆ์„ ํ•œ๋‹ค.
  • ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ Override๋œ successfulAuthentication()์„ ํ†ตํ•ด ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์™€ ๊ทธ๊ฒƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ† ํฐ์„ ์ƒ์„ฑํ•ด ํ—ค๋”๋กœ ๋„ฃ์–ด์ค€๋‹ค.
  • ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋กœ๊ทธ์•„์›ƒ๊นŒ์ง€ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— redis์—๋„ ํ† ํฐ์„ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

 

JwtAuthorizationFilter.java - ์ธ์ฆ&์ธ๊ฐ€

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private final JwtProvider jwtProvider;
    private final JwtValidator jwtValidator;
    private final JwtAuthenticator jwtAuthenticator;
    private final RedisService redisService;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, JwtProvider jwtProvider, JwtValidator jwtValidator, JwtAuthenticator jwtAuthenticator, RedisService redisService) {
        super(authenticationManager);
        this.jwtProvider = jwtProvider;
        this.jwtValidator = jwtValidator;
        this.jwtAuthenticator = jwtAuthenticator;
        this.redisService = redisService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String header = request.getHeader(JwtProperties.TOKEN_HEADER_KEY.getKey());

        if (header == null || !header.startsWith(JwtProperties.AUTH_TYPE.getKey())) {
            chain.doFilter(request, response);
            return;
        }

        String token = jwtProvider.getResolvedToken(request, JwtProperties.AUTH_TYPE.getKey());

        Authentication authentication = getAuthentication(token);

        if (token != null && jwtValidator.validateAccessToken(token)) {
            if(!redisService.getData((String) authentication.getPrincipal()).equals(token)) {
                throw new RuntimeException(ErrorMessages.TOKEN_MISMATCH.getMessage());
            }
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }

    private Authentication getAuthentication(String token) {
        PrincipalDetails principalDetails = (PrincipalDetails) jwtAuthenticator.getAuthentication(token).getPrincipal();

        return new UsernamePasswordAuthenticationToken(
                principalDetails.getLoginId(), principalDetails.getPassword(), principalDetails.getAuthorities()
        );
    }
}
  • ํ† ํฐ์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด SecurityContext์— ์ €์žฅํ•œ๋‹ค.
  • Redis์—๋„ ํ† ํฐ์„ ๋„ฃ์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ถ”๊ฐ€์ ์œผ๋กœ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค.

=> ์ด๋ ‡๊ฒŒ ๊ฑฐ์น˜๊ฒŒ ๋˜๋ฉด ์ธ์ฆ ๊ฐ์ฒด์ธ Authentication (์‹ค์งˆ์ ์œผ๋กœ UsernamePasswordAuthentication์ด์ง€๋งŒ ์–˜๊ฐ€ ํ•˜์œ„ํด๋ž˜์Šค์ด๋ฏ€๋กœ ๋Œ€์‹  ์ด์šฉํ•˜๊ฒ„์ง€)๋ฅผ SecurityConfig์— ์ •์˜ํ•œ๋Œ€๋กœ role์„ ์ฒดํฌํ•ด ๊ถŒํ•œ ๋ถ€์—ฌ๊ฐ€ ์ด๋ฃจ์–ด์ ธ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

Logout - ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค ์ด์šฉ

.and()
.logout()
.logoutUrl("/logout")
.addLogoutHandler((request, response, authentication) -> {
    String token =
            jwtProvider.getResolvedToken(request, JwtProperties.TOKEN_HEADER_KEY.getKey());

    redisService.deleteData(token);
})
.logoutSuccessHandler((request, response, authentication) -> response.getWriter().write("Logout succeed"))

=> ์œ„์—์„œ ๋ณด์…จ๋‹ค์‹œํ”ผ ๋žŒ๋‹ค์‹์œผ๋กœ ๊ฐ„ํŽธํ™”๋œ ๋‚ด๋ถ€ ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ์ •์˜ ํ•ด Redis์—์„œ ํ† ํฐ์„ ์‚ญ์ œํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋กœ๊ทธ์•„์›ƒ์„ ๊ฐ„๋‹จํžˆ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

์ฐธ์กฐ : https://catsbi.oopy.io/f9b0d83c-4775-47da-9c81-2261851fe0d0

 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ฃผ์š” ์•„ํ‚คํ…์ฒ˜ ์ดํ•ด

๋ชฉ์ฐจ

catsbi.oopy.io

๋‹ค์Œ์—” ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๊ณผ์ •์„ ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค~

๋ฐ˜์‘ํ˜•