본 시리즈는 작성자의 이해와 경험을 바탕으로 실습 위주의 설명을 기반으로 작성되었습니다.
실습 위주의 이해를 목표로 하기 때문에 다소 과장이 많고 생략된 부분이 많을 수 있습니다.
따라서, 이론적으로 미흡한 부분이 있을 수 있는 점에 대해 유의하시기 바랍니다.
또한, 본 시리즈는 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
정보에 접근합니다.