이제 DB에 저장된 유저 정보를 load하는 부분을 만들어야 한다.
@RequiredArgsConstructor
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userData = userRepository.findByLoginId(username).orElseThrow(() -> new CustomException(ErrorCode.NOT_EXIST_USER));
//DTO에 넣어서 전달, 이 DTO는 UserDetails를 구현한 DTO로 직접 만들어야 함
return new CustomUserDetails(userData);
}
}
public class CustomUserDetails implements UserDetails {
private final User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collection = new ArrayList<>();
collection.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole().toString();
}
});
return collection;
}
@Override
public String getPassword() {
return user.getCredentials().getHashedPassword();
}
@Override
public String getUsername() {
return user.getLoginId();
}
후략
}
설정파일을 수정한다
//AuthenticationManager가 인자로 받을 AuthenticationConfiguraion 객체 생성자 주입
private final AuthenticationConfiguration authenticationConfiguration;
private final JWTProvider jwtProvider;
public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTProvider jwtProvider) {
this.authenticationConfiguration = authenticationConfiguration;
this.jwtProvider = jwtProvider;
}
http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtProvider), UsernamePasswordAuthenticationFilter.class);
import java.util.Collection;
import java.util.Iterator;
@RequiredArgsConstructor
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private final JWTProvider jwtProvider;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String userName = obtainUsername(request);
String password = obtainPassword(request);
//Authentication Mangager에 던지기 전에 DTO에 담아줘야 한다.
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userName, password, null);
return authenticationManager.authenticate(authToken);
}
//로그인 성공 시 실행하는 메소드
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) {
CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
String userName = customUserDetails.getUsername();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Iterator<? extends GrantedAuthority> iterator = authorities.iterator();
GrantedAuthority auth = iterator.next();
String role = auth.getAuthority();
String token = jwtProvider.createToken(userName, role);
response.addHeader("Authorization", "Bearer " + token);
}
//로그인 실패시 실행하는 메소드
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
request.setAttribute("401", "Unauthorized");
}
}
@RequiredArgsConstructor
public class JWTFilter extends OncePerRequestFilter {
private final JWTProvider jwtProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
if (authorization == null || !authorization.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
}
String token = authorization.split(" ")[1];
//토큰 소멸 시간 검증
if (jwtProvider.isExpired(token)) {
filterChain.doFilter(request, response);
return;
}
String username = jwtProvider.getUsername(token);
String roleString = jwtProvider.getRole(token);
Role role = roleString.equals("ROLE_USER") ? Role.ROLE_USER : Role.ROLE_ADMIN;
User user = User.builder().loginId(username).role(role).build();
CustomUserDetails customUserDetails = new CustomUserDetails(user);
//스프링 시큐리티 인증 토큰 생성
Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
//세션에 사용자 등록
SecurityContextHolder.getContext().setAuthentication(authToken);
filterChain.doFilter(request, response);
}
}
필터까지 등록해준다.