
본 시리즈는 작성자의 이해와 경험을 바탕으로 실습 위주의 설명을 기반으로 작성되었습니다.
실습 위주의 이해를 목표로 하기 때문에 다소 과장이 많고 생략된 부분이 많을 수 있습니다.
따라서, 이론적으로 미흡한 부분이 있을 수 있는 점에 대해 유의하시기 바랍니다.
또한, 본 시리즈는 ChatGPT의 도움을 받아 작성되었습니다.
수 차례의 질문을 통해 도출된 여러가지 다양한 방식의 코드를 종합하여
작성자의 이해와 경험을 바탕으로 가장 정석으로 생각되는 코드를 재정립하였습니다.
Spring Security에서 인증에 사용하기 위한User정보를 담은 객체.
public interface UserDetails를implements하여CustomUserDetails로 커스텀.
SpringBoot WebSecurity에서JWT(JSON Web Token)의 데이터 흐름은 다음과 같습니다.
CustomUserDetails->CustomUserDetailsService->
JwtTokenProvider->JwtTokenFilter->WebSecurityConfig
CustomUserDetails.java
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;
public class CustomUserDetails implements UserDetails {
private final User user;
// Constructor
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority(user.getRole().name()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public Long getId() {
return user.getId();
}
public String getEmail() {
return user.getEmail();
}
public String getContact() {
return user.getContact();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public String getPassword() {
return user.getPassword();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
public interface UserDetails를User.java를 기반으로implements한다.
쉽게 말하면User.java에Authority가 추가된CustomUser Class인 느낌이다.
Spring Security의UserDetails를 사용하기 위한Service.
public interface UserDetailsService를implements하여
CustomUserDetailsService로 커스텀.
SpringBoot WebSecurity에서JWT(JSON Web Token)의 데이터 흐름은 다음과 같습니다.
CustomUserDetails->CustomUserDetailsService->
JwtTokenProvider->JwtTokenFilter->WebSecurityConfig
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository; // 별도로 생성해야 함
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username).orElseThrow(
() -> new UsernameNotFoundException("해당 유저가 존재하지 않습니다. username = " + username));
return new CustomUserDetails(user); // 위에서 생성한 CustomUserDetails Class
}
// 필요시 추가
public UserDetails loadUserByUserId(Long userId) throws IllegalArgumentException {
User user = userRepository.findById(userId).orElseThrow(
() -> new IllegalArgumentException("해당 유저가 존재하지 않습니다. user_id = " + userId));
return new CustomUserDetails(user);
}
// 필요시 추가
public UserDetails loadUserByEmail(String email) throws IllegalArgumentException {
User user = userRepository.findByEmail(email).orElseThrow(
() -> new IllegalArgumentException("해당 유저가 존재하지 않습니다. email = " + email));
return new CustomUserDetails(user);
}
}
public interface UserDetailsService를User.java를 기반으로implements한다.
UserRepository를 통해User Entity에 접근하고Authority가 추가된
CustomUserDetails객체를 반환하는 과정을 거친다.
필요에 따라
user_id,user_email등을 기반으로User Entity를 찾는 메소드
loadUserByUserId(),loadUserByEmail()등을 구현해서 사용한다.예를 들어, 프로젝트 요구사항에 따라
Github처럼username이 중복을 허용하는 경우
id,User정보에 접근합니다.