관리 메뉴

샐님은 개발중

[세션5] Authentication Provider(인증 제공자) 본문

Spring Security - udemy

[세션5] Authentication Provider(인증 제공자)

샐님 2024. 8. 21. 09:50
728x90
반응형

맞춤 AuthenticationProvider를 생성해야 하는 이유 

 - Spring Security 의 기본 AuthenticationProviders 를 활용하는데 그것은 DaoAuthenticationProvider 입니다. 

- 개발자가 할일은 개인세부정보를 들고와서 암호를 구성, 개인세부정보를 DaoAuthenticationProvider에 넣게 되면 제 DaoAuthenticationProvider은 엔드 유저를 인증하는 일을 함. 비밀번호 비교/ 계정 만료 여부/ 신임장 만료 여부 

- 이 DaoAuthenticationProvider는 우리가 엔드 유저 인증 도중에 고려하고 싶은 대부분의 시나리오를 제공

- 그리고 DaoAuthenticationProvider 안에는 기본 구현논리는 충분하지만 실제 사용 환경에서 엔드 유저 인증시 다소 복잡한 요구사항들을 마주하게 됨.

- 사용자 세부사항을 저장 시스템에서 가져오는 것과 별개로 우리는 우리만의 인증 논리를 실행하길 원함.

ex) 사용자가 18세 이상만 / 허용 국가 존재 등

 

-> 이러한 이유 때문에 맞춤 AuthenticationProvider  가 필요함 

 

AuthenticationProvider 메소드의 이해

public interface AuthenticationProvider {

	/**
	 * Performs authentication with the same contract as
	 * {@link org.springframework.security.authentication.AuthenticationManager#authenticate(Authentication)}
	 * .
	 * @param authentication the authentication request object.
	 * @return a fully authenticated object including credentials. May return
	 * <code>null</code> if the <code>AuthenticationProvider</code> is unable to support
	 * authentication of the passed <code>Authentication</code> object. In such a case,
	 * the next <code>AuthenticationProvider</code> that supports the presented
	 * <code>Authentication</code> class will be tried.
	 * @throws AuthenticationException if authentication fails.
	 */
	Authentication authenticate(Authentication authentication) throws AuthenticationException;

	/**
	 * Returns <code>true</code> if this <Code>AuthenticationProvider</code> supports the
	 * indicated <Code>Authentication</code> object.
	 * <p>
	 * Returning <code>true</code> does not guarantee an
	 * <code>AuthenticationProvider</code> will be able to authenticate the presented
	 * <code>Authentication</code> object. It simply indicates it can support closer
	 * evaluation of it. An <code>AuthenticationProvider</code> can still return
	 * <code>null</code> from the {@link #authenticate(Authentication)} method to indicate
	 * another <code>AuthenticationProvider</code> should be tried.
	 * </p>
	 * <p>
	 * Selection of an <code>AuthenticationProvider</code> capable of performing
	 * authentication is conducted at runtime the <code>ProviderManager</code>.
	 * </p>
	 * @param authentication
	 * @return <code>true</code> if the implementation can more closely evaluate the
	 * <code>Authentication</code> class presented
	 */
	boolean supports(Class<?> authentication);

}

AuthenticationProvider 인터페이스 내 2가지 추상메소드 존재

1. authenticate : 여러분이 인증 논리 작성시 필요한 메소드. 입력값은  Spring Securtiy 필터들에 의해 발생한 엔드 유저의 유저 이름과 신임증이 포함된 인증 객체.  성공적인 인증 정보를 생산하고 있는지 인증 객체를 출력값으로 작성하고 있는지 확인함. 하지만 이번엔 우리가 AuthenticationProviders로부터 출력하는 인증 객체 안에서 그것이 인증이 성공적이었는지에 대한 정보를 가지고 있어야 ProviderManager 가 가용 가능한 다른 AuthenticationProviders를 불러올지 판단 가능.

 

2. supports : 이 메소드를 사용하려면 Spring Security 에서 AuthenticationProviders의 도움으로 지원하고 싶은 인증의 종류를 알려주어야함. 가장 일반적으로 사용되는 인증 방식은 유저 이름과 비밀번호의 도움을 받는 것.

유저 이름과 비밀번호 인증의 형태로 지원하고 싶다면  "나는 유저 이름 비밀번호 인증 방식을 지원하고 싶다"라고 지원 방식 내에서 언급해줘야함. 이 메소드를 사용하는 것은 Spring Security 프레임워크에서 어떤 인증의 종류에 제 AuthenticationProviders가 부름을 받아야 하는지 말하는 것. 

 

애플리케이션 내 AuthenticationProvider 구현 및 커스터마이징

package woncom.wonCommunity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import woncom.wonCommunity.domain.Customer;
import woncom.wonCommunity.repository.CustomerRepository;

import java.util.ArrayList;
import java.util.List;
@Component
public class WonUsernamePwdAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private CustomerRepository customerRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String username = authentication.getName();
        String pwd = authentication.getCredentials().toString();
        List<Customer> customer = customerRepository.findByUserId(username);
        if(customer.size()>0){
            if(passwordEncoder.matches(pwd, customer.get(0).getPwd())){
                List<GrantedAuthority> authorities = new ArrayList<>();
                authorities.add(new SimpleGrantedAuthority(customer.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 (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

 

 

 

728x90
반응형