해당 포스팅은 스프링 시큐리티 6.0.3을 기준으로 합니다.
-------------------------------------------------------------------------------------------------------
스프링 시큐리티 하위버전의 경우 WebMvcSecurityConfiguration을 extends을 상속받아
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{
authenticationManagerBuilder.userDetailsService(LoginService);
}
configure 메소드를 오버라이드 하고
AuthenticationManagerBuilder 객체를 변수로 받아서 해당 변수에 로그인 로직을 지정한 클래스를 변수로 넣어줄 수 있었는데.
3.x버전 이상에서는 WebMvcSecurityConfiguration가 디프리케이티드 되다 보니. AuthenticationProvider를 상속받아 구현하고 Bean으로 Bean을 등록하는 방식으로 처리해야 한다.
(구버전에서도 프로바이더 생성해서 인증 및 권한처리 진행한다.)
이하 상세.
1. 가장 먼저 UserDetails를 반환하는 클래스를 생성해야 한다.
UserDetails는 스프링 시큐리티가 사용자의 정보를 담기 위해 만들어놓은 인터페이스다.
UserDetails 자체를 implements해도 되고, UserDetails의 구현체인 User클래스를 extends 받아도 된다.(시큐리티에서 구현해놓음)
나는 User클래스 상속받았다.
public class MemberLoginContext extends User {
private final Member member;
/**
* 로그인 시 계정 정보 생성
* @param member
* @param authorities
*/
public MemberLoginContext(Member member, Collection<? extends GrantedAuthority> authorities) {
super(member.getUserNickName(),member.getPassword(), authorities);
this.member = member;
}
public Member getMember(){
return member;
}
}
2. 두 번째로 로그인 관련 로직을 처리할 로그인 서비스 클래스를 생성한다.
해당 클래스는 시큐리티에서 제공하는 UserDetailService를 상속받아서 UserDetails를 반환하는 메소드(loadUserByUsername)를 오버라이드 해야 한다.
@Service
@RequiredArgsConstructor
public class LoginService implements UserDetailsService {
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String userNickName) throws UsernameNotFoundException {
Member member = memberRepository.findByUserNickName(userNickName)
.orElseThrow(() -> new UserNotFoundException("회원을 찾을 수 없습니다.", userNickName));
//권한 부여
List<GrantedAuthority> roles = new ArrayList<>();
roles.add(new SimpleGrantedAuthority(member.getRole()));
MemberLoginContext memberLoginContext = new MemberLoginContext(member,roles);
return memberLoginContext;
}
}
loadUserByUsername은 1에서 만든 클래스( UserDetails의 구현체 User를 상속받은)
3. AuthenticationProvider을 상속받아 구현한다
->AuthenticationProvider는 시큐리티에서 사용자 인증을 처리하기 위해 제공하는 인터페이스인데 해당 인터페이스를 구현받아 인증 절차를 거칠 때 2에서 만든 LoginService를 사용한다.
-> 생성자로 패스워드 인코더를 받는다.
-> Authentication 메소드를 오버라이드한다. 리턴 타입으로 스프링 시큐리티가 제공하는 인증토큰 클래스(UsernamePasswordAuthenticationToken)를 반환.
-> UsernamePasswordAuthenticationToken는 변수로 (
principal(식별자), credentials(비밀번호)입니다. authorities(사용자의 권한 목록
) 을받는다.
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private LoginService loginService;
@Autowired
private PasswordEncoder passwordEncoder;
public CustomAuthenticationProvider(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Override
@Transactional
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userNickName = authentication.getName();
String password = (String) authentication.getCredentials();
MemberLoginContext memberLoginContext = (MemberLoginContext) loginService.loadUserByUsername(userNickName);
if (!passwordEncoder.matches(password, memberLoginContext.getMember().getPassword())) {
throw new BadCredentialsException("Invalid Password");
}
return new UsernamePasswordAuthenticationToken(memberLoginContext.getMember(), null, memberLoginContext.getAuthorities());
}
4. 시큐리티 설정 클래스에 AuthenticationProvider 구현체를 반환하도록 Bean을 등록한다.
(굳이 설정 클래스에 하지 않아도 되지만, 앞으로 등록할 프로바이더 관련 Bean이 여러개이므로 그냥 설정 클래스에 등록하는게 나은것 같다)
-> AuthenticationProvider의 구현체를 Bean으로 등록하면 AuthenticationManager의 구현체인 ProviderManager가
AuthenticationProvider의 구현체를 참조해서 인증처리를 진행한다.
AuthenticationProvider
@Bean
public CustomAuthenticationProvider customAuthenticationProvider() {
return new CustomAuthenticationProvider(passwordEncoder());
}
5. 로그인해보면 정상적으로 처리되는걸 확인
끗
'스프링시큐리티' 카테고리의 다른 글
[스프링시큐리티 맨땅부터 적용하기] 1. 프로젝트 생성 및 gradle 설정 (1) | 2024.01.03 |
---|---|
[스프링시큐리티] 커스텀 Login 화면과 csrf (0) | 2023.07.26 |
[스프링시큐리티] 권한(Authority) & 역할(Role)에 따른 페이지 인가 (0) | 2023.07.23 |
[스프링 시큐리티] 스프링시큐리티 -1(시큐리티 인가 및 인증) (0) | 2023.07.21 |
[스프링 시큐리티] 0.스프링시큐리티 설치 및 설정 (0) | 2023.07.21 |