UserDetailsService
UserDetailsService의 주요 기능은 사용자와 관련된 상세 데이터를 로드하는 것이며
사용자의 신원, 권한, 자격 증명 등과 같은 정보를 포함할 수 있다
이 인터페이를 사용하는 클래스는 주로 AuthenticationProvider 이며
사용자가 시스템에 존재하는지 여부와 사용자 데이터를 검색하고 인증 과정을 수행한다
사용자의 이름을 통해 사용자 데이터를 검색하고, 해당 데이터를 UserDetails 객체로 반환한다
UserDetailsService 흐름도
UserDetailsService 사용 방법
위의 userDetailService() 메소드를 사용한것처럼 직접 POJO객체를 등록해도 되지만
아래처럼 @Bean을 이용해서 빈등록을 하는것이 사용성에 유리하다. [ 빈 등록방식을 사용하자.]
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return User.withUsername("user").password("{noop}1111").roles("USER").build(); }
}
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
;
return http.build();
}
@Bean
public UserDetailsService customUserDetailsService(){
return new CustomUserDetailsService();
}
}
@Component
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String loginId = authentication.getName();
String password = (String)authentication.getCredentials();
//아이디 검증
UserDetails user = userDetailsService.loadUserByUsername(loginId);
if(user == null) throw new UsernameNotFoundException("UsernameNotFoundException");
//비밀번호 검증
return new UsernamePasswordAuthenticationToken
(user.getUsername(), user.getPassword(), user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
}
}
사용자 상세 - UserDetails
UserDetails
• 사용자의 기본 정보를 저장하는 인터페이스로서 Spring Security 에서 사용 하는 사용자 타입이다
• 저장된 사용자 정보는 추후에 인증 절차에서 사용되기 위해
Authentication 객체에 포함되며 구현체로서 User 클래스가 제공된다
public class User implements UserDetails, CredentialsContainer
default boolean isCredentialsNonExpired() {
return true;
}
• 사용자의 비밀번호가 유효 기간이 지났는지를 확인하며 유효 기간이 지난 비밀번호는 인증할 수 없다
default boolean isAccountNonExpired() {
return true;
}
• 사용자 계정의 유효 기간이 지났는지를 나타내며 기간이 만료된 계정은 인증 할 수 없다
String getUsername();
• 사용자 인증에 사용된 사용자 이름을 반환하며 null 을 반환할 수 없다
Collection<? extends GrantedAuthority> getAuthorities();
• 사용자에게 부여된 권한을 반환하며 null을 반환할 수 없다
default boolean isAccountNonLocked() {
return true;
}
• 사용자가 잠겨 있는지 아닌지를 나타내며 잠긴 사용자는 인증할 수 없다
tring getPassword();
• 사용자 인증에 사용된 비밀번호를 반환한다
default boolean isEnabled() {
return true;
}
• 사용자가 활성화되었는지 비활성화되었는지를 나타내며 비활성화된 사용자는 인증할 수 없다
@Getter
@AllArgsConstructor
public class AccountDto {
private String username;
private String password;
private Collection<GrantedAuthority> authorities;
}
UserInfo == AccountDto
public class CustomUserDetails implements UserDetails {
private final AccountDto accountDto;
public CustomUserDetails(AccountDto accountDto){
this.accountDto = accountDto;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return accountDto.getAuthorities();
}
@Override
public String getPassword() {
return accountDto.getPassword();
}
@Override
public String getUsername() {
return accountDto.getUsername();
}
@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 class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AccountDto accountDto = new AccountDto("user", "{noop}1111", List.of(new SimpleGrantedAuthority("ROLE_USER")));
return new CustomUserDetails(accountDto);
}
}
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
;
return http.build();
}
@Bean
public UserDetailsService customUserDetailsService(){
return new CustomUserDetailsService();
}
}
@Component
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String loginId = authentication.getName();
String password = (String)authentication.getCredentials();
//아이디 검증
UserDetails user = userDetailsService.loadUserByUsername(loginId);
if(user == null) throw new UsernameNotFoundException("UsernameNotFoundException");
//비밀번호 검증
return new UsernamePasswordAuthenticationToken
(user.getUsername(), user.getPassword(), user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
}
}
'인프런 > 스프링 시큐리티 완전 정복 [6.x 개정판]' 카테고리의 다른 글
12)스프링 MVC 로그인 구현 (1) | 2024.10.21 |
---|---|
11) 인증 상태 영속성 - SecurityContextRepository & SecurityContextHolderFilter (1) | 2024.10.18 |
9) 인증 제공자 - AuthenticationProvider (1) | 2024.10.16 |
8) 인증 관리자 - AuthenticationManager (1) | 2024.10.15 |
7) 인증 아키텍처 - Authentication , SecurityContext / SecurityContextHolder (1) | 2024.10.14 |
댓글