네이버 로그인 API를 활용한 소셜로그인 구현 과정(with. Spring Security, JWT) - 5. JwtAuthenticationProvider class 생성

Sia Hwang·2022년 11월 29일
0

이번 포스트에서는 실질적인 시용자 인증 처리 및 JWT 생성 처리를 하는 JwtAuthenticationProvider 클래스를 작성할 것이다.

JwtAuthenticationProvider class

import com.august.soil.api.service.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;

@RequiredArgsConstructor
public class JwtAuthenticationProvider implements AuthenticationProvider {
  
  private final Jwt jwt;
  
  private final UserService userService;
}
  • AuthenticationProvider 인터페이스를 구현한 클래스를 생성한다.
  • JWT 정보를 저장할 필드와 서비스단 참조변수를 멤버로 생성한다.
  • 생성자에서 별다른 액션을 할 것이 없어서 @RequiredArgsConstructor를 사용해 final 키워드가 붙은 멤버변수들을 초기화 해 주었다.
import com.august.soil.api.service.user.UserService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ClassUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;

@RequiredArgsConstructor
public class JwtAuthenticationProvider implements AuthenticationProvider {
  
  ...
  
  /**
   * {@link org.springframework.security.authentication.ProviderManager#authenticate} 메소드에서 호출된다.
   *
   * true 를 리턴하면 현재 Provider 에서 인증 처리를 할 수 있음을 의미한다.
   * 본 Provider 에서는 {@link JwtAuthenticationToken} 타입의 {@link Authentication} 를 처리할 수 있다.
   */
  @Override
  public boolean supports(Class<?> authentication) {
    return ClassUtils.isAssignable(JwtAuthenticationToken.class, authentication);
  }
}
  • ClassUtils.isAssignable 메서드를 통해 전달받은 authenticationJwtAuthenticationToken 클래스에 할당 가능한지(클래스 본인이거나 자식클래스이거나) 확인한다.
  • 우리 서버에서는 JwtAuthenticationToken 객체를 인증 토큰으로 사용하기 때문에 JwtAuthenticationToken 타입을 매개변수로 받았을 때 true를 리턴할 것이다.
import com.august.soil.api.error.NotFoundException;
import com.august.soil.api.model.user.Email;
import com.august.soil.api.model.user.Role;
import com.august.soil.api.model.user.User;
import com.august.soil.api.service.user.UserService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ClassUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@RequiredArgsConstructor
public class JwtAuthenticationProvider implements AuthenticationProvider {
  
  ...
  
  /**
   * {@link org.springframework.security.authentication.ProviderManager#authenticate} 메소드에서 호출된다.
   *
   * null 이 아닌 값을 반환하면 인증 처리가 완료된다.
   */
  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) authentication;
    return processUserAuthentication(authenticationToken.authenticationRequest());
  }
  
  private Authentication processUserAuthentication(AuthenticationRequest request) {
    try {
      User user = userService.login(new Email(request.getPrincipal()), request.getCredentials());
      JwtAuthenticationToken authenticated =
        // 응답용 Authentication 인스턴스를 생성한다.
        // JwtAuthenticationToken.principal 부분에는 JwtAuthentication 인스턴스가 set 된다.
        // 로그인 완료 전 JwtAuthenticationToken.principal 부분은 Email 인스턴스가 set 되어 있었다.
        new JwtAuthenticationToken(new JwtAuthentication(user.getId(), user.getName(), user.getEmail()), null, AuthorityUtils.createAuthorityList(Role.USER.getValue()));
      // JWT 값을 생성한다.
      // 권한은 ROLE_USER 를 부여한다.
      String apiToken = user.newApiToken(jwt, new String[]{Role.USER.getValue()});
      authenticated.setDetails(new AuthenticationResult(apiToken, user));
      return authenticated;
    } catch (NotFoundException e) {
      throw new UsernameNotFoundException(e.getMessage());
    } catch (IllegalArgumentException e) {
      throw new BadCredentialsException(e.getMessage());
    } catch (DataAccessException e) {
      throw new AuthenticationServiceException(e.getMessage(), e);
    }
  }
}
  • 인증처리를 하는 메서드를 오버라이딩한다.
  • null이 아닌 값을 반환하면 인증처리가 완료된 것이다.

Entry on Spring Security Configure

@Component
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfigure {

  private final Jwt jwt;
  
  @Bean
  public JwtAuthenticationProvider jwtAuthenticationProvider(Jwt jwt, UserService userService) {
    return new JwtAuthenticationProvider(jwt, userService);
  }
  • Web security 관련 처리를 할 클래스를 만들어서 아까 만든 클래스를 빈으로 등록한다.

코드 전문 : https://github.com/miro7923/soil/blob/main/soil/src/main/java/com/august/soil/api/security/JwtAuthenticationProvider.java

다음 포스트에서 계속...

profile
당면한 문제는 끝까지 해결하기 위해 노력하는 주니어 개발자입니다.

0개의 댓글