이번 포스트에서는 실질적인 시용자 인증 처리 및 JWT 생성 처리를 하는
JwtAuthenticationProvider
클래스를 작성할 것이다.
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
메서드를 통해 전달받은 authentication
이 JwtAuthenticationToken
클래스에 할당 가능한지(클래스 본인이거나 자식클래스이거나) 확인한다. 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
이 아닌 값을 반환하면 인증처리가 완료된 것이다. @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
관련 처리를 할 클래스를 만들어서 아까 만든 클래스를 빈으로 등록한다. 다음 포스트에서 계속...