스프링

OAuth2.0과 JWT적용 - 3

winwin-k9 2023. 1. 25. 22:17

처음 들어오는 사용자가 OAuth로그인 후 -> 처음 들어오는 사용자면 DB에 정보 저장후 -> 토큰 발급

 

이러한 로직을 수행하려고 한다.

 

우선 Controller를 먼저 구성해보자

@RestController
@RequiredArgsConstructor
public class MemberController {

    private final OAuthService oAuthService;

    @GetMapping("/oauth/login")
    public ResponseEntity<Token> loginController(@AuthenticationPrincipal OAuth2User oAuth2User) {
        return ResponseEntity.ok(oAuthService.login(oAuth2User.getAttributes()));
    }
}

return되는 저것은 우선 신경쓰지 말자.

전에 구성했던 OAuthUserService를이용해 loadUser로 대항 OAuth인증을 하는 사용자 정보를 가지고 온다. 

(https://winwin-k9.tistory.com/106 이전글은 여기 참고)

 

스프링 시큐리티는 SecurityContext에 인증된 Authentication 객체를 넣어두고 현재 스레드 내에서 공유되도록 관리한다.

 

OAuthService

@Service
@RequiredArgsConstructor
public class OAuthService {
    private final MemberRepository memberRepository;
    private final TokenService tokenService;

    @Transactional
    public Token login(Map<String, Object> attribute) {
        String email = (String) attribute.get("email");
        String name = (String) attribute.get("name");
        if (memberRepository.findByEmail(email) == null) {
            Member member = new Member(email, name);
            memberRepository.save(member);
        }
        return tokenService.generateToken(email, name);
    }
}

 

OAuth인증 사용자로 부터 Attribute를 가져온다. 인증된 사용자의 Attribute는 속성으로 Map구조로 되어있다.

이 정보를 받아서 해당 유저가 DB에 이미 저장이 되어있지 않으면 정보를 저장(회원가입 처리)후

토큰을 발급해주도록 한다.

 

다음은 Security설정이다.

 

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final OAuthUserService oAuthUserService;
    private final JwtFilter jwtFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf().disable()
                .authorizeHttpRequests().anyRequest().permitAll()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER) //세션사용 안함
                .and()
                .formLogin()
                .and()
                .oauth2Login()  //OAuthLogin 설정
                .userInfoEndpoint() // oauth2Login 설정을 시작
                .userService(oAuthUserService) // 로그인을 oAuthUserService에서 처리
                .and()
                .defaultSuccessUrl("/oauth/login");
        http.addFilter(jwtFilter);

        return http.build();
    }
}

 

OAuth로그인이 끝나면 url이 defaultSuccessUrl인 /oauth/login 으로 이동하게 된다.

여기서 오류가 발생하는데

 

does not have a registered order and cannot be added without a specified order

addFilter는 메서드를 사용하기 위해서는 반드시 Spring Security Framework 에서 제공되는 필터 혹은 이를 확장한 객체이어야 한다. 

따라서 addFilterBefore나 After를 사용해야 한다.

 

따라서 다음과 같이 변경해야 한다.

http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);

UsernamePasswordAuthenticationFilter는 Form인증을 처리하는 필터이다.

사용자가 로그인하면 인증처리가 이루어지는데, 이 인증처리를 담당하고 관련된 요청을 처리한다.

 

 

http://localhost:8080/oauth2/authorization/google

OAuth인증을 하는 해당 URL로 접속후, 로그인을 하면

아래와 같이 토큰을 발급받는것을 확인할 수 있다.

728x90