Posts
Q&A
์๋ ํ์ธ์. ์ ์๋ ๊ฐ์๋ฅผ ๋ณด๊ณ ํ์ฌ OAuth2 + JWT ์ธ์ฆ ์ธ๊ฐ๋ฅผ ๊ตฌํ ์ค์ธ๋ฐ... ์ง๋ฌธ์ ๋๋ ค๋ ๋ ๊น์?
์ ๋ง ๊ฐ์ฌํฉ๋๋ค. ์์ง ํ ์คํธ๋ ๋ ํด๋ด์ผ๊ฒ ์ง๋ง, ์๋ ค์ฃผ์๊ณ ์กฐ์ธ ํด์ฃผ์ ๊ฒ๋ค์ ๋ฐํ์ผ๋ก ๋๋์ด ๊ตฌํ์ ์ฑ๊ณต ํ์ต๋๋ค. ๊ตฌํ์๋ ์ฑ๊ณต ํ์์ง๋ง ์ํ ์ฐฉ์ค๋ฅผ ๊ฒช์๋ ๊ณผ์ ์์ ์ดํดํ์ง ๋ชปํ ๊ฒ๋ค์ด ์์ด ๋ช ๊ฐ์ง ์ง๋ฌธ์ ๋๋ฆฌ๊ณ ์ถ์ต๋๋ค. (์๋ง๋ ๋ง์ง๋ง ์ง๋ฌธ์ด ๋ ๊ฑฐ ๊ฐ์ต๋๋ค.) 1. ์์ ์ง๋ฌธ์์ 2๋ฒ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์์ AbstractAuthenticationToken์ ์์ํ์ฌ ์ปค์คํ ํ ํฐ์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์๋ ค ์ฃผ์ จ์ต๋๋ค. ๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ด AuthenticationToken์ ์ถ๊ฐ ํ๋๋ฐ์. public class CustomJwtAuthenticationToken extends AbstractAuthenticationToken { private final OAuthAccount oAuthAccount; private final String jwtToken; @Builder private CustomJwtAuthenticationToken(OAuthAccount oAuthAccount, String jwtToken) { super(oAuthAccount.getAuthorities()); this.oAuthAccount = oAuthAccount; this.jwtToken = jwtToken; } @Override public Object getCredentials() { return jwtToken; } @Override public Object getPrincipal() { return oAuthAccount; }} ์ด๋ฅผ ์ปค์คํ ํํฐ์์ UsernamePasswordAuthenticationToken ๋์ ์์ฑ ํ๊ณ SecurityContextHolder์ ์ ์ฅ ํ์๋๋ฐ, ์์ฒญ ํ ์คํธ๋ฅผ ํด๋ณด๋ StackoverflowError Exception์ด ๋ฐ์ ํ์์ต๋๋ค. ์ด์ 3๋ฒ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ AuthenticationManager ๋ ๋ถ๋ชจ AuthenticationManager ๊ฐ์ฒด๋ฅผ ๊ฐ์ง ์ ์๊ณ ์ฌ๊ทํด์ ์ ์ ํ AuthenticationProvider ๋ฅผ ์ฐพ๋๋ค๊ณ ๋์ด ์์ต๋๋ค. ๋ผ๋ ๋ด์ฉ์ด ์์์ต๋๋ค. SecurityConfig์ ์์๋ก ์์ฑํ AuthenticationManager๋ฅผ ๋ฃ์ด ์ฃผ์์ง๋ง, ์ธ์ฆ ๊ณผ์ ์์ AuthenticationProvider๋ฅผ ์ฐพ์ง ๋ชปํ์ฌ ์ฌ๊ท๊ฐ ๋ฐ์ํ์ฌ ์๊ธด ์์ธ๋ผ ์ถ์ธก์ ํ๊ณ ์๋๋ฐ, ์ด ๊ฒ์ด ๋ง์๊น์? Custom ํ ํฐ์ด ์๋ ๊ธฐ์กด์ ์๋ UsernamePasswordAuthenticationToken์ ์ฌ์ฉํ๋ฉด ํด๋น ์์ธ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. 2. JWT๋ฅผ ์ธ์ฆํ๋ ์ปค์คํ ํํฐ์์ OAuthAccount oAuthAccount = OAuthAccount.from(account);Authentication authentication = new UsernamePasswordAuthenticationToken(oAuthAccount, jwtToken, oAuthAccount.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication); ์์ ๊ฐ์ด UsernamePasswordAuthenticationToken์ credentials์ jwtToken์ ๋ฃ์ด์ฃผ๊ณ ์์ง๋ง, ์ด์ ์ฒ๋ผ ์ด ๋ถ๋ถ์ ๋น์๋์ด๋ ๋ฌธ์ ๊ฐ ์๊ธฐ์ง ์๋๋ฐ์. (๊ฐ์ ๋ฐ๊ฟ ๋ณด์๋ ์ ์ ์๋ ํ๋ ๊ฒ์ ํ์ธํ ์ ์์์ต๋๋ค.) ์ด์ ๊ฐ์ด ํ ํฐ์ ์ง์ ์์ฑํ๋ ๊ณผ์ ์์ credentials ํ๋๊ฐ ์ด๋ค ์๋ฏธ๋ฅผ ๊ฐ์ง๋๊ฑด์ง ์๊ณ ์ถ์ต๋๋ค. 3. ๊ธฐ์กด์๋ ์ปค์คํ ์ธ์ฆ ํํฐ๊ฐ BasicAuthenticationFilter๋ฅผ ์์ํ๋๋ก ๊ตฌํ์ ํ์๋๋ฐ, ํด๋น ํํฐ ์์์๋ authenticationManager์ ์ญํ ์ด ์ ํ ์๋ค๊ณ ์๊ฐ๋์ด OncePerRequestFilter๋ฅผ ์์ ํ๋๋ก ์์ ํด๋์ ์ํ ์ ๋๋ค. ์ด ์ญ์ ์ฝ๋๊ฐ ๋ฌธ์ ์์ด ์๋์ ํ๋๋ฐ, ์์ฐํ ์ธ์ฆ ์ฒ๋ฆฌ๋ฅผ ๋์ ํ๋ ํํฐ์ด๊ธฐ ๋๋ฌธ์ BasicAuthenticationFilter๋ฅผ ์์ํ๋๋ก ๊ตฌํ ํ๋๊ฒ ๋ง๋๊ฑด์ง ํ๋จ์ ์ด๋ ค์ด ์ ์ด ์์ต๋๋ค. BasicAuthenticationFilter๊ฐ OncePerRequestFilter๋ฅผ ์์ํ๋ ํํฐ๋ผ๋ ๊ฒ์ ์๊ณ ์๋๋ฐ, ์ด๋ค ํํฐ๋ฅผ ์์ํ๋๋ก ํ๋๊ฒ ๋ ์ณ์ ์ชฝ์ผ๊น์? ์ฌ๊ธฐ๊น์ง ์๋ง๋ ๋ง์ง๋ง์ผ๋ก ๋๋ฆฌ๋ ์ง๋ฌธ์ด ๋ ๊ฑฐ ๊ฐ์ต๋๋ค. ์ํ๋ฆฌํฐ๊ฐ ๊ณต๋ถํ ์๋ฃ๋ ์ถฉ๋ถํ์ง ์๊ณ ๊ณต์ ๋ฌธ์๋ ์น์ ํํธ์ด ์๋๋ผ ์ด๋ ค์์ด ๋ง์๋๋ฐ์. ์ ๊ณตํด์ฃผ์ ๊ฐ์๋ฅผ ํตํด ์ ์ฉ์ ์๋ํด๋ณผ ์ ์์๊ณ , ์ธ์ฆ / ์ธ๊ฐ์ ๊ฐ๋ ์ ๋ค์ง๋๋ฐ์๋ ์ ๋ง ๋ง์ ๋์์ ๋ฐ์์ต๋๋ค. ๋ค์ ํ๋ฒ ๊ฐ์ฌ๋ฅผ ๋๋ฆฝ๋๋ค. ์ฌ์ ํ ์ด๋ ต๊ณ ๋ชจ๋ฅด๋๊ฒ ๋ง์ง๋ง ์ด๋ฒ ๊ตฌํ ๊ณผ์ ์์ ์ข ๋ ํ์ต์ด ๋ ๋๋์ธ๋ฐ์. ํ๋ก์ ํธ๋ฅผ ๋ง๋ฌด๋ฆฌ ํ๋ฉด ๋จ์ ์ค์ ๊ฐ์๋ ๋๊น์ง ์๊ฐํ๊ณ ์๊ฐํ๋ ๋จ๊ธฐ๊ฒ ์ต๋๋ค :) ๋์ ์ฃผ์ ์ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค.
- 0
- 6
- 860
Q&A
์๋ ํ์ธ์. ์ ์๋ ๊ฐ์๋ฅผ ๋ณด๊ณ ํ์ฌ OAuth2 + JWT ์ธ์ฆ ์ธ๊ฐ๋ฅผ ๊ตฌํ ์ค์ธ๋ฐ... ์ง๋ฌธ์ ๋๋ ค๋ ๋ ๊น์?
์ ์๋, ๋จผ์ ์์ธํ ๋ต๋ณ ํด์ฃผ์ ์ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค :) ์๋ ค์ฃผ์ ๊ฒ์ ๋ฐํ์ผ๋ก ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ๋ค์ ์์ ํ๋ ค ์๋๋ฅผ ํ๊ณ ์๋๋ฐ์. ์ ํด๊ฒฐ ๋์ง ์๋ ๋ถ๋ถ๋ค์ด ์์ด ๋ถ๋์ดํ๊ฒ ์ถ๊ฐ ์ง๋ฌธ์ ๋๋ฆฌ๊ฒ ๋์์ต๋๋ค. ๋จผ์ ์ํ๋ฆฌํฐ๊ฐ ๋ด๋ถ์ ์ผ๋ก OAuth2LoginAuthenticationProvider๋ฅผ ํตํด OAuth2LoginAuthenticationToken์ ์์ฑํ์ฌ, ์ด๋ฅผ SecurityContextHolder์ ์ ์ฅ ํ๋ ๊ณผ์ ์ ๋๋ฒ๊ฑฐ๋ฅผ ํตํด ํ์ธ ํ์์ต๋๋ค. ๋ฌธ์ ๋ ๋ง์ ํ์ ๊ฒ์ฒ๋ผ JWT ์ธ์ฆ๋ฐฉ์์ ์๋์ ๊ฐ์ ์ค์ ์ผ๋ก http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); ์ธ์ ์ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์, ์ธ๊ฐ ํ๋ก์ธ์ค ์ด์ ์ SecurityContext์ Authentication์ ๋ณ๋๋ก ์ ์ฅํด์ฃผ์ด์ผ ํ๋ค๋ ์ ์ ๋๋ค. ๊ทธ๋์ ์ ๊ฐ ์ฒ์์ ์๋ ํ๋ ๋ฐฉ๋ฒ์ UsernamePasswordAuthenticationToken์ ์๋์ผ๋ก ์์ฑํด์ SecurityContext์ ๋ฃ์ด์ฃผ๋ ๋ฐฉ๋ฒ์ด์์ต๋๋ค. ์ฌ์ค ์ด ๋ฐฉ๋ฒ์ ํํ๋ ์ด์ ๋, OAuth2LoginAuthenticationToken์ ๋ํด ์์งํ๊ณ ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ด์๋๊ฑฐ ๊ฐ์ต๋๋ค. ๊ธฐ์กด ์ธ์ฆ / ์ธ๊ฐ ์ฒ๋ฆฌ ํ๋ฆ์ ๋ฌธ์ ๋ ์๋ค๊ณ ๋ง์์ ํด์ฃผ์ จ๊ณ , ์ ๊ฐ ์ต์ข ์ ์ผ๋ก ๊ตฌํํ๊ณ ์ถ์ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. 1. ๋ค์๊ณผ ๊ฐ์ด ์ธ์ฆ์ด ๋๋ ์ฌ์ฉ์๊ฐ BasicAuthenticationFilter ๋ฅผ ๊ฑฐ์ณ๊ฐ ๋ (์ธ๊ฐ ์ฒ๋ฆฌ ํํฐ์ ๋๋ฌํ๊ธฐ ์ด์ ์) @Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { AccountClaims accountClaims = jwtTokenProvider.parseJwtToken(request.getHeader(HttpHeaders.AUTHORIZATION)); Account account = accountRepository.findByEmail(accountClaims.getEmail()).orElseThrow(AccountNotFoundException::new); OAuthAccount oAuthAccount = OAuthAccount.from(account); Authentication authentication = new UsernamePasswordAuthenticationToken(oAuthAccount, null, oAuthAccount.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(request, response);} JWT๋ฅผ ๊ฒ์ฆํ๊ณ , ๊ฒ์ฆ๋ ์ฌ์ฉ์๋ผ๋ฉด UserDetails ํ์ ํน์ OAuth2User ๋ฅผ implement ํ ๊ฐ์ฒด(Authentication)๋ฅผ ์์ฑํ์ฌ SecurityContextHolder์ ์ ์ฅํ๋ค. 2. ์ฌ์ฉ์์ ๋ํ ์ธ๊ฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.3. ์ธ๊ฐ ์ฒ๋ฆฌ๊ฐ ๋๋ ์ฌ์ฉ์๊ฐ ์ปจํธ๋กค๋ฌ์ ๋๋ฌํ๋ฉด, SecurityContextHolder์์ ๊บผ๋ด์ด ์ดํ ์ฒ๋ฆฌ๋ฅผ ์งํํ๋ค. ์ ๋๋ค. ์ฌ๊ธฐ์ ๊ถ๊ธํ ์ ์ด ์์ต๋๋ค. 1. ์ฒ์ ์ง๋ฌธ์์ ์ค๋ช ๋๋ฆฐ๊ฒ๊ณผ ๊ฐ์ด OAuth2๋ก ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ ๋ค ์ดํ์๋ JWT ํ ํฐ์ ํตํด ์ธ์ฆ / ์ธ๊ฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ ํ๋ฆ ์ธ๋ฐ์.SecurityContext์ Authentication์ ๋ฃ์ด์ฃผ๋ ๊ณผ์ ์์ OAuth2LoginAuthenticationToken์ด ์๋ UsernamePasswordAuthenticationToken์ ์ฌ์ฉํด๋ ๋ฌธ์ ๊ฐ ์์๊น์? 2. ๋ง์ฝ UsernamePasswordAuthenticationToken์ ์ฌ์ฉํด๋ ๊ด์ฐฎ๋ค๋ฉด, UserDetails ํ์ ์ผ๋ก ๋๊ธฐ์ง ์๊ณ OAuth2User ํ์ ์ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ๋ ์๊ด์ด ์์๊น์? (UserDetails๋ก ์์ฑํ๋ ๊ฒ์ด ๋ ๊ฐ๋จํ ๋ฏ ํ์ง๋ง, Password๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ ๊ฒ์ด ๊ฑธ๋ฆฌ๋ ์ ๊ฐ์ต๋๋ค.)3. UsernamePasswordAuthenticationToken์ ์ฌ์ฉํด๋ ๊ด์ฐฎ์ ๊ฒฝ์ฐ, ์ฌ๊ธฐ์ ๊ถ๊ธํ ๊ฒ์ด AuthenticationManager์ ์ญํ ์ ๋๋ค. ๊ธฐ์กด ์ฝ๋์ ์๋์ ๊ฐ์ด ์ํ๋ฆฌํฐ ์ค์ ์ด ๋์ด ์์ต๋๋ค. @RequiredArgsConstructor@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { // ... @Override protected void configure(HttpSecurity http) throws Exception { // ... http.addFilterBefore(JwtAuthorizationFilter.of(authenticationManager(), accountRepository, jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); // ... } @Override @Bean protected AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); }} BasicAuthenticationFilter๋ฅผ extends ํ๋ ค๋ฉด ๋ฐ๋์ authenticationManager ๋ฅผ ์์ฑ์์ ๋ฃ์ด์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ @Override@Beanprotected AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager();} ์์ ์ฝ๋๋ฅผ ์ถ๊ฐ ํ๋ ๊ฒ์ธ๋ฐ์. ์ ์๋ ๊ฐ์๋ฅผ ํตํด AuthenticationManager์ ์ญํ ์ด ์ธ์ฆ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ ์ธํฐํ์ด์ค๋ผ ๋ฐฐ์ ์์ต๋๋ค.๋ฌธ์ ๋ ์์ ๋ก๊ทธ์ธ์ด๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์๊ฐ OAuth๋ฅผ ํตํด ์ธ์ฆ์ ํ๋ ๊ณผ์ ์์ AuthenticationManager๋ฅผ ๋ณ๋๋ก ์ฌ์ฉํ์ง ์์๋๋ฐ, ์ด๋ ๊ฒ ์์๋ก ๋ฃ์ด ํํฐ๋ฅผ ์์ฑํ ๋ค ๋ค์๊ณผ ๊ฐ์ด @Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { AccountClaims accountClaims = jwtTokenProvider.parseJwtToken(request.getHeader(HttpHeaders.AUTHORIZATION)); Account account = accountRepository.findByEmail(accountClaims.getEmail()).orElseThrow(AccountNotFoundException::new); OAuthAccount oAuthAccount = OAuthAccount.from(account); Authentication authentication = new UsernamePasswordAuthenticationToken(oAuthAccount, null, oAuthAccount.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(request, response);} ๊ตฌํํด๋ ๋ฌธ์ ๊ฐ ์์๊น์? 4. ๋ง์ฝ ๋ฐ๋์ OAuth2LoginAuthenticationToken์ ์ฌ์ฉํด์ผ ํ๋ค๋ฉด public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration, OAuth2AuthorizationExchange authorizationExchange, OAuth2User principal, Collectionextends GrantedAuthority> authorities, OAuth2AccessToken accessToken) { this(clientRegistration, authorizationExchange, principal, authorities, accessToken, null);} ์ด ์์ฑ์๋ฅผ ํตํด ์์ฑ์ ํ๋ ๋ฏ ๋ณด์ด๋๋ฐ์. (OAuth2AccessToken์ด ์๋ ๊ฒ์ผ๋ก ๋ด์๋ OAuth Authorization ์๋ฒ์ ํต์ ์ ํ๋ ๊ณผ์ ์์ ์ฐ์ด๋ ๊ฒ ๊ฐ๊ธฐ๋ ํ๋ฐ...) ์ด ๊ฒ๋ค์ ํํฐ์์ ์์ฑํ๊ณ ํ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋์ง ๊ถ๊ธํฉ๋๋ค. ํ๋ก์ ํธ๋ฅผ ์์ํ๋ฉด์๋ถํฐ ์ํ๋ฆฌํฐ๋ฅผ ํตํ OAuth2 + JWT ์ฌ์ฉ์ ์ธ์ฆ / ์ธ๊ฐ์ ๋ํด ์ ๋ง ๋ง์ด ์ฐพ์๋ดค์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ์๋ฃ๋ ๋ง์ด ์๊ณ ์ฌ์ ํ ๋ต์ ์ฐพ์ง ๋ชปํ๊ณ ์๋ค์ใ ใ ์ํ๋ฆฌํฐ์ ์ธ์ฆ / ์ธ๊ฐ ์ฒ๋ฆฌ๊ฐ ๋งค์ฐ ๊ฒฌ๊ณ ํ๊ณ ๊ฐ๋ ฅํ๋ค๊ณ ๋๋ผ๊ณ ์๊ธฐ ๋๋ฌธ์ JWT๋ฅผ ์ ์ฉํ๋ ๊ณผ์ ์์ ๊ผญ ์ฌ์ฉ ํด๋ณด๊ณ ์ถ์๋ฐ... ์ฝ์ง ์๋ค์. ์กฐ์ธ์ ๋ถํ ๋๋ฆฝ๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
- 0
- 6
- 860
Q&A
์คํ๋ง ๋ฐ์ดํฐ JPA์ JPQL์ ํจ๊ป ์ฌ์ฉํ ๊ฒฝ์ฐ Repository์ ๋ํด ์ง๋ฌธ ๋๋ฆฝ๋๋ค.
๊ฐ์๋ฅผ ๋ฃ๊ณ ๋ฐฐ์ฐ๋ฉด์ ๋จธ๋ฆฟ์์ ํญ์ ์๋ ์๋ฌธ์ด์๋๋ฐ ์ํ๋ ๋ต๋ณ์ผ๋ก ๋ง์ ๋ถ๋ถ์ด ํด์๊ฐ ๋์์ต๋๋ค. ๋ง์ ํด์ฃผ์ ๋ฐฉํฅ์ผ๋ก ๊ฐ์ธ ํ๋ก์ ํธ๋ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค! ์กฐ์ธ ํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค^^
- 0
- 2
- 425