
UserDetailsService:
。Spring Security에서인증 / 인가 작업을 수행 시인증정보를 포함하는UserDetails의조회를 위해DB에 저장된사용자정보를UserDetails 객체로서 조회하여 제공하는Core Interface
。AutheticationProvider에 의해 호출되어DB에서 저장된사용자정보를 조회 및 해당하는 사용자정보를 포함하는UserDetails 구현체를 생성해서 전달하는 역할을 수행.
▶AutheticationProvider는Authentication 구현체의Credentials와UserDetails 구현체의Password를 비교하여사용자인증의검증을 수행.
UserDetailsService.loadUserByUsername("username"):
。DB에서 해당자격증명의ID에 해당하는사용자 정보를 조회 후UserDetails 객체로 반환하는구현 메서드
。세션 로그인시@Service Class에서 해당UserDetailsService 인터페이스를 구현 후 해당구현 메서드를 구현해야한다.
▶JWT 로그인시는 구현할 필요가 없음.@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Optional<Member> memberByUserName = memberRepository.findMemberByUserName(username); Member member = memberByUserName.orElseThrow( () -> new UsernameNotFoundException("해당 회원을 찾을 수 없음") ); return new CustomUserDetails( member.getUserName(), member.getPassword(), member.getRole() ); }。
검증수행 시AuthenticationProvider에게DB에서 가져온사용자 정보를 포함한UserDetails DTO를 생성 후 반환
▶AutheticationProvider는 해당 기능을 통해인증에 필요한사용자 정보를 포함하는UserDetails 구현체를 전달 받아서 검증에 활용
UserDetails:
。Spring Security의인증 / 인가에 필요한사용자별 세부인증 정보를 저장하는DTO 역할의Core Interface.
▶인증 작업수행 시UserDetailsService에 의해DB에 저장된사용자의이름, PW, 권한등의세부정보를 포함한UserDetails 구현체생성 후AuthenticationProvider에게 반환
。UserDetails 구현체는User 클래스를 사용하거나,커스텀 UserDetails 구현 클래스를 정의해서 생성 가능
UserDetails 구현클래스는DTO 역할을 수행
。ex )~/dto 디렉토리내 저장
。어떤서비스를 개발함에 따라로그인한회원이 가져야 하는 데이터는 다양하며,커스텀 UserDetails 구현체를 통해필요 정보만 포함하도록 설정
ex )배민의로그인한유저는주소정보가 있어야한다.
。UserDetails 구현체는원본 유저 테이블에 저장된데이터를 추출하여Spring Security에 의해인증이 수행되는DTO 역할을 수행한다.
▶ID / PW / Authority외 더 필요한 정보를 추가 가능
。JWT를 통한검증시에도UserDetails 구현체는DTO로서 사용됨@RestController @RequestMapping("/api/profiles") public class ProfileController { @GetMapping("/me") public ResponseEntity<?> getMyProfile( @AuthenticationPrincipal CurrentUser currentUser ) { UUID userId = currentUser.getId(); String email = currentUser.getEmail(); return ResponseEntity.ok("유저 ID: " + userId + ", 이메일: " + email); } }▶
인증이후인메모리 DB에 저장되며Controller에@AuthenticationPrincipal을 통해 해당 정보로 주입됨
Lombok의@Getter를 통해추상메서드를 축약한커스텀 UserDetails 구현체생성 가능
。UserDetails 인터페이스를구현및UserDetails 구현 클래스생성 시추상메서드:getUsername(), getPassword(), getAuthorities()에 따른usename / password / role 필드만 반드시 정의하고, 나머지필드 정보는DTO로서 선택적으로 추가해서 정의@Getter @RequiredArgsConstructor public class CurrentUser implements UserDetails { private final String username; private final String password; private final String role; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of( new SimpleGrantedAuthority(role) ); } }▶ 나머지
부정검사를 수행하는구현메서드:isAccountNonExpired(), isAccountNonLocked(), isCredentialsNonExpired(), isEnabled()의 경우 선택적으로구현
- 세션 로그인에서의
UserDetails 구현체
。세션 로그인시UserDetailsService.loadUserByUsername("username")에 의해DB에서 가져온사용자 정보를 포함한UserDetails DTO를 생성 후AuthenticationProvider에게 반환함으로써Spring Security에 의해 식별
User:
。UserDetails를 구현한구현체
▶UserDetails는인터페이스이므로 직접 Instance를 생성할 수 없으므로UserClass의Builder로ID, PW, Role를 지정하여UserDetails 구현체생성.
User.build():
。UserDetailsInstance를 생성
User.builder():
。User.withDefaultPasswordEncoder()에서 비밀번호 알고리즘(.passwordEncoder())을 추가 정의하여UserDetails 객체를 생성하는Builder Method.
▶User.withDefaultPasswordEncoder()를 대체.
User객체.passwordEncoder(input -> 패스워드인코더().encode(input)):
。Spring Bean으로 사전등록한 특정PasswordEncoder( ex.BCryptPasswordEncoder)를 통해문자열을인코딩하여 반환하는함수형 인터페이스를 정의하여 해당UserDetails객체의PasswordEncoder를 설정
▶ 사전에@Configuration Class에서PasswordEncoder의@Bean method가 존재해야 사용가능private UserDetails getUserDetails(String username, String password,roles role){ // User.passwordEncoder(람다식)을 통해 input된 문자열을 PasswordEncoder 구현 Class를 통해 // `Hashing`으로 Encoding을 수행하여 Hash값을 반환. return User.builder().passwordEncoder((input)-> passwordEncoderB().encode(input) ).username(username).password(password).roles(role.toString(),"DEVELOPER").build(); }