개요
- 스프링 시큐리티에서 기본적으로 UserDetailsService 를 제공해 주지만, 프로젝트에 맞게 커스텀할 일이 생기기 마련이다.
- 디비에서 사용자 정보를 가져와서 AuthenticationProvider 에게 UserDetails 타입의 유저 정보를 넘겨주는 UserDetailsService 를 직접 구현해 보려고 한다.
UserDetailsService
- 위와 같이 UserDtailsService 는 UserRepository 로 부터 데이터를 가져와서 AuthenticationProvider 에게 UserDetails 타입의 유저 정보를 만들어서 넘겨준다.
코드
- Account 엔티티 구현
@Entity
@Data
@EqualsAndHashCode(of = "id")
@NoArgsConstructor
@AllArgsConstructor
public class Account implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column
private String username;
@Column
private String email;
@Column
private int age;
@Column
private String password;
@Column
private String role;
}
- UserRepository 인터페이스 구현
public interface UserRepository extends JpaRepository<Account, Long> {
Account findByUsername(String username);
}
- AccountContext 클래스 구현
public class AccountContext extends User {
private final Account account;
public AccountContext(Account account, Collection<? extends GrantedAuthority> authorities) {
super(account.getUsername(), account.getPassword(), authorities);
this.account = account;
}
public Account getAccount() {
return account;
}
}
- User 를 상속받는 AccountContext 를 구현한다.
- 여기서 User 는 스프링 시큐리티에서 제공하는 User 이다.
- 밑에서 구현한 CustomUserDetailsService의 loadUserByUsername 메소드의 반환값으로 UserDetails 타입의 객체가 반환되어야 하기 때문에, UserDtails 를 구현하고 있는 User 객체를 상속받는 클래스로 구현한 것이다.
- CustomUserDetailsService 클래스 (이 부분이 중요하다.)
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = userRepository.findByUsername(username);
if(account == null){
throw new UsernameNotFoundException("UsernameNotFoundException");
}
List<GrantedAuthority> roles = new ArrayList<>();
roles.add(new SimpleGrantedAuthority(account.getRole()));
AccountContext accountContext = new AccountContext(account, roles);
return accountContext;
}
}
- 위와 같이 loadUserByUsername 메소드를 오버라이드해서 재정의 해준다.
- userRepository 로 부터 데이터를 불러온다. -> 존재하지 않는다면 UsernameNotFoundException 예외를 던진다.
- UserDetails 타입으로 반환해야 되기 때문에 위에서 구현한 AccountContext 으로 감싸서 반환한다.
SecurityConfig 에 CustomUserDetailService 등록
private final UserDetailsServie userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailService(userDetailsService);
}
- 위와 같이 직접 구현한 userDetailsService 를 등록해 줌으로써, 스프링 시큐리티에서 기본적으로 제공하는 UserDetailsService 를 사용하지 않고 직접 구현한 CustomUserDetailService 를 사용할 수 있다.
REFERENCES
- 정수원님의 스프링 시큐리티
'Spring Security' 카테고리의 다른 글
ExceptionTranslationFilter,RequestCacheAwareFilter (0) | 2022.02.28 |
---|---|
Security Filter (0) | 2022.02.28 |
AuthenticationSuccessHandler, AuthenticationFailureHandler, AccessDeniedHandler 커스텀하기 (0) | 2022.02.28 |
UsernamePasswordAuthenticationFilter 커스텀 하기 (0) | 2022.02.28 |
WebAuthenticationDetails 와 AuthenticationDetailsSource (0) | 2022.02.28 |