Spring Security 메모 - AuthenticationProvider

timothy jeong·2022년 7월 17일
0

Spring Security

목록 보기
4/8

Spring Security AuthenticationProvider

[image:792BF2A6-DB5E-46BE-B472-D4E76005037D-37344-00000DCA38FAF258/스크린샷 2022-07-05 오전 9.57.09.png]

Spring Security 가 활성화되면 클라이언트에서 들어오는 http 요청은 AuthenticationFilter 에 의해 Authentication 객체로 보내지고, 그 객체에서 validate 를 거친 다음에 AuthenticationManager 에게 전달된다. 그 뒤에
AuthenticationProvider 에 전달되어 여기서 UserDetailService 와 PasswordEncoder 등이 활용된다.

만약 이러한 과정이 아니라 특별한 요구사항에 따라 Authentication 과정을 변경해야 한다면 어떻게 해야할까?

어떤 특별한 요구사항이 있을 수 있을까? 기보적인 ID, passwd 프로세스가 아니라 생체인증 정보, OTP code 등으로 Authentication 이 가능하게 하려면 커스터마이징을 할 수밖에 없다.

커스터마이징

public interface AuthenticationProvider {Authentication authenticate(Authentication authentication) 
		throws AuthenticationException; 
	
	boolean supports(Class<?> authentication); 
} 

이 인터페이스에서 authenticate 메서드를 override 해서 authenticate를 커스터마이징 할 수 있다.

Support 메서드를 override 하여 주어진 authentication 객체가 authenticate 할 수 있는지 여부를 반환한다.

Authentication Manager 는 어플리케이션에 존재하는 모든 Authentication Provider 를 돌려가면서 Authentication 이 가능한지 판단하는 책임만 갖는다.

AuthenticationObject

이 객체는 UserDetails 객체와는 어떤게 다른걸까

[image:35A7847C-EB03-4485-8F91-C500DD5D92E8-37344-00000E35CE79846A/스크린샷 2022-07-05 오후 4.31.56.png]
AuthenticationObject 는 Authentication 과정에서 모든 User 의 Detail 들과 관련된 정보를 다룬다.

getDetails() 메서드는 유저의 접속 IP 정보도 가지고 있다. 그런데 우리는 Authentication 과정에서 오로지 UserDetails 객체와 관련된 작업만 하지 않았나?

AbstractUserDetailsAuthenticationProvider 라는 객체에서 둘을 컨버팅한다.
더 자세하게는 createSuccessAuthentication 메서드가 UserDetails 를 받아서 Authentication 객체를 반환한다.

아니 근데 왜 동일한 과정에서 UserDetails 과 Authentication 이 나눠지는걸까?
스프링 시큐리티는 개발자에게 자율성을 주기 위해서 이렇게 한다.

AuthenticationProvider 커스터마이징

@Component
public class BackPwdAuthenticationProvider implements AuthenticationProvider {

    private final CustomerRepository customerRepository;
    private final PasswordEncoder passwordEncoder;

    @Autowired
    public BackPwdAuthenticationProvider(CustomerRepository repository, PasswordEncoder passwordEncoder) {
        this.customerRepository = repository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String pwd = authentication.getCredentials().toString();
        List<Customer> customers = customerRepository.findByEmail(username);
        if (customers.size() > 0) {
            if (passwordEncoder.matches(pwd, customers.get(0).getPwd())) {
                List<GrantedAuthority> authorities = new ArrayList<>();
                authorities.add(new SimpleGrantedAuthority(customers.get(0).getRole()));
                return new UsernamePasswordAuthenticationToken(username, pwd, authorities);
            } else {
                throw new BadCredentialsException("Invalid password");
            }

        } else {
            throw new BadCredentialsException("No user registered with this details!");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

AuthenticationProvider 는 하나의 스프링 부트 안에서 여러개를 만들 수 있다. 그리고
AuthenticationManger 는 등록된 모든 AuthenticationProvider 를 모두 모아서 하나라도 통과되는지 확인한다.

profile
개발자

0개의 댓글