반응형
https://yeo-computerclass.tistory.com/347
위 포스팅한 글을 먼저 읽고오는 것을 추천한다.
UserDetailsService
위 글에서 "UserDetailsService 인터페이스의 구현체가 사용자의 정보와 사용자가 가진 권한 정보를 반환한다." 하였다.
이런 처리 과정에 대해 설명하도록 하겠다.
- UserDetailsService는 로그인 처리를 위한 사용자의 정보를 가져올 때 username과 password를 동시에 가져와 사용하지 않는다.
- 일단 username을 이용하여 사용자의 존재를 판단한 후에
- password를 가져와 틀리면 인증 실패라는 결과를 반환하고
- 일치할 경우(인증 과정 끝) 원하는 URL에 접근할 수 있는 권한(인가)이 있는지 판단한다.
- UserDetailsService는 UserDetails 인터페이스를 구현한 것
- UserDetails 인터페이스는 loadUserByUsername() 메소드 하나만 가지고 있다. 이를 구현한 UserDetailsService 역시 loadUserByUsername() 메소드 하나만을 갖는다.
- loadUserByUsername(): username이라는 회원 아이디를 이용하여 회원 정보를 Load 한다.
때문에 Spring Security에서는 username이라는 식별 데이터를 사용한다. - loadUserByUsername()의 반환 타입: UserDetails
- getUsername(): 인증에 필요한 아이디 정보
- getPassword(): 인증에 필요한 비밀번호 정보
- getAuthorities(): 사용자의 권한에 대한 정보
- Spring Security에서는 사용자 자체 혹은 계정에 대해 User라는 용어를 사용한다.
주의!: User라는 용어와 겹치지 않게 주의할 필요가 있다.
회원을 처리하기 위한 구현
SecurityConfig 구현 & DB에 값 넣어놓기 등이 준비되어야 한다.
이에 대해 궁금하다면 다음 링크 참고하도록 하자! + 아래는 SecurityConfig 코드이다.
SecurityConfig 코드
@Configuration
@Log4j2
public class SecurityConfig {
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((auth) -> {
auth.antMatchers("/sample/all").permitAll();
auth.antMatchers("/sample/member").hasRole("USER");
});
http.formLogin();
http.csrf().disable();
http.logout();
return http.build();
}
}
1. UserDetails 인터페이스 구현
회원의 정보와 가진 권한 정보를 처리하기 위해서는 두 가지 방법을 생각해 볼 수 있다.
- 기존 DTO 클래스에 UserDetails 인터페이스를 구현하기
- UserDetails를 구현한 클래스인 User를 상속하는 별도의 클래스(DTO) 만들기
두 번째 방법으로 구현하도록 하겠다.
Member Entity 클래스
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Member extends DateEntity {
@Id
private String email;
private String password;
private String name;
private boolean joinSocial;
@ElementCollection(fetch = FetchType.LAZY)
@Builder.Default
private Set<MemberRole> roleSet = new HashSet<>();
public void addMemberRole(MemberRole memberRole){
roleSet.add(memberRole);
}
}
AuthMemberDTO extends User
@Log4j2
@Getter
@Setter
@ToString
public class AuthMemberDTO extends User {
private String email;
private String name;
private boolean joinSocial;
public AuthMemberDTO(String username, String password, boolean joinSocial, Collection<? extends GrantedAuthority> authorities){
super(username, password, authorities);
this.email = username;
this.joinSocial = joinSocial;
}
}
- Member Entity 클래스와 호환되는 DTO 역할을 수행하는 클래스
- Spring Security 인가 / 인증 작업에 사용할 수 있는 클래스
- UserDetailsService의 반환 타입이 UserDetails이고 이 클래스는 UserDetails를 구현한 User 클래스를 상속받았다.
- password 필드는 User 부모 클래스를 사용하였기 때문에 따로 선언하지 않았다.
2. UserDetailsService 구현
@Log4j2
@Service
@RequiredArgsConstructor
public class PracUserDetailsService implements UserDetailsService {
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username: " + username);
Optional<Member> result = memberRepository.findByEmail(username, false);
if(result.isEmpty()){
throw new UsernameNotFoundException("Check Email / Social");
}
Member member = result.get();
log.info(member);
//Entity -> DTO(+Auth)
AuthMemberDTO authMemberDTO = new AuthMemberDTO(
member.getEmail(),
member.getPassword(),
member.isJoinSocial(),
member.getRoleSet().stream().map(role->
new SimpleGrantedAuthority("ROLE_" + role.name())).collect(Collectors.toList())
//.name() : Enum 자체적인 메소드, 상수를 String으로 반환
);
log.info("authoMemberDTO");
log.info(authMemberDTO);
authMemberDTO.setName(member.getName());
log.info(authMemberDTO);
return authMemberDTO;
}
}
- UserDetailsService를 구현한 Service 클래스
- loadUserByUsername 메소드를 구현해주어야 한다. 이때 반환값은 UserDetails이다.
authMemberDTO는 UserDetails의 구현 클래스인 User를 상속한 클래스이므로 이에 만족한다.
3. 결과
http://localhost:8080/sample/member 접속
DB에 없는 값 입력 시
올바른 값 입력 시 (DB에 저장되어 있는 값 + ROLE_USER 권한 갖는 회원)
참고 - 코드로 배우는 스프링 부트 웹 프로젝트
반응형
'Spring Framework' 카테고리의 다른 글
Spring web.xml, root-context.xml, servlet-context.xml (0) | 2023.05.23 |
---|---|
Spring @ControllAdvice와 @ExceptionHandler로 전역 예외처리 하기 (0) | 2022.10.25 |
Spring Thymeleaf 살펴보기 (0) | 2022.10.06 |
Spring ResponseEntity (0) | 2022.09.21 |
Spring Redirect: 다른 URL로 리다이렉트 (0) | 2022.09.14 |