오늘은 Spring Security의 인증 절차 인터페이스인 UserDetailsService에 대해서 알아보고 구현해보도록 하겠습니다.
UserDetailsService 인터페이스는 DB에서 유저 정보를 가져오는 역할을 담당합니다. 해당 인터페이스의 메소드에서 DB의 유저 정보를 가져와서 AuthenticationProvider 인터페이스로 유저 정보를 리턴하면, 그 곳에서 사용자가 입력한 로그인 정보와 비교합니다.
🧐 1. UserDetails
UserDetails 인터페이스는 Spring Security가 사용자 정보를 알 수 있도록 사용자의 정보를 담는 인터페이스입니다. 이 인터페이스를 구현하면 Spring Security에서 구현 클래스를 사용자 정보로 인식하고 인증 작업을 하게 됩니다.
UserDetails 인터페이스에는 오버라이딩해야할 메소드들이 있는데, 이 메소드들의 역할은 다음과 같습니다.
| 메소드명 | 리턴 타입 | 설명 |
| getAuthorities() | Collection<? extends GrantedAuthority> | 계정이 갖고 있는 권한 목록을 리턴 |
| getPassword() | String | 계정 패스워드 리턴 |
| getUsername() | String | 계정 이름(ID)를 리턴 |
| isAccountNonExpired() | boolean | 계정이 만료되지 않았는지 리턴 |
| isAccountNonLocked() | boolean | 계정이 잠겨있지 않았는지 리턴 |
| isCredentialNonExpired() | boolean | 비밀번호가 만료되지 않았는지 리턴 |
| isEnabled() | boolean | 계정이 활성화(사용가능)인 지 리턴 |
계정이 만료되있는지, 계정이 잠겨있는지 등에 대해서는 체크할 필요가 없다면 true를 리턴하면 됩니다.
또한, 체크할 멤버 변수가 존재한다면, 그 멤버 변수를 리턴해주면 됩니다.
CustomUserDetails.java
public class CustomUserDetails implements UserDetails {
private String email;
private String password;
private String Authority;
private boolean enabled; // 계정 활성화 여부
private String name;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
auth.add(new SimpleGrantedAuthority(AUTHORITY));
return auth;
}
@Override
public String getUsername() {
return email;
}
@Override
public String getPassword(){
return password;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isEnabled() {
return ENABLED;
}
// 오버라이드 아님 , 프로젝트에 맞게 커스터마이징
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
🧐 2. UserDetailsService
사용자의 정보를 담을 객체를 만들었으니, DB에서 유저 정보를 직접 가져오는 인터페이스를 구현해보겠습니다.
userDetailsService 인터페이스에는 DB에서 유저 정보를 불러오는 메소드인 loadUserByUsername() 가 존재합니다. 이 메소드를 오버라이딩해서 유저 정보를 불러옵니다. 여기서, CustomUserDetails 타입으로 사용자의 정보를 가져오고 사용자의 정보가 null/not null 에 따라 예외와 사용자 정보를 리턴해주면 됩니다.
CustomUserDetailsService.java
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserAuthDao userAuthDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
CustomUserDetails user = userAuthDAO.getUserById(username);
if(user==null) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
loadUserByUsername() 을 오버라이딩하고 사용자 정보를 CustomUserDetails 타입으로 받은 후,
null 여부를 확인하고 null 이라면 예외 처리, 아니라면 사용자 정보를 그대로 리턴합니다.
🧐 3. UserDetailsService를 통한 인증 과정
AuthenticationProvider는 인증 로직에서 UserDetailsService를 통해 DB에 저장된 User의 세부정보를 획득합니다.

후에 User의 encodedPassword(PasswordEncoder에 의해 암호화되어 DB에 저장되었던 password)와 사용자가 로그인 요청시 입력했던 password가 일치하는지 PasswordEncoder를 이용하여 비교하는 로직을 진행합니다.
비교 후 값이 동일할 경우, 결과를 AuthenticationFilter에 전달하고 세부정보(Authentication 객체)가 SecurityContext에 저장됩니다.
만약 값이 동일하지 않을 경우 일반적으로는 클라이언트에 HTTP 401 status code가 반환됩니다.
'Spring' 카테고리의 다른 글
| [Spring] @ResquestBody, @ResponseBody (0) | 2023.12.08 |
|---|---|
| [Spring] ResponseEntity란 (0) | 2023.12.07 |
| [Spring] 싱글톤 방식의 주의점 (0) | 2023.06.14 |
| [Spring] 스프링이란? (0) | 2023.06.01 |
| [Spring] Spring Security (0) | 2023.05.25 |