라이브러리는 도서관 아닌가요

AuthenticationProvider 구현 본문

Spring/Spring Security

AuthenticationProvider 구현

veryhi 2021. 12. 30. 07:02

 

AuthenticationProvider 인터페이스는

 

유저가 입력한 정보

 

DB가 가지고 있는 정보를 비교해준다.

 

개발 중에 아주 유용한 도구로 활용될 수도 있다.

 

뭐, 사용자 입력 값을 중간에 확인해 본다던지 하는 그런.

 

 

 

이것이 가능한 이유는,

 

요 인터페이스에 오버라이딩 해야하는 authenticate() 메서드가

 

'유저가 입력한 로그인 정보'를 가지고 있는 Authentication 객체를 다루기 때문이다.

 

 

 

정확하게는 파라미터(Authentication authentication)로 받는다.

 

'유저의 입력 정보' 뿐만 아니라 '권한 정보'도 가지고 있다.

 

 

 

반대로 DB 측의 정보는

 

UserDetailsService 인터페이스에서 구현한

 

loadUserByUsername() 메서드를 통해 가지고 온다.

 

이름을 봐서 알다시피 파라미터로 username을 사용하고,

 

반환형은 인터페이스 UserDetails다.

 

UserDetails user로 선언하고 받았을 때, 

 

user.getUsername();

user.getPassword();

 

따위로 접근할 수 있다.

 

 

 

인증 매니저(Authentication Manager)가 DB의 데이터에 접근할 때,

 

바로 이 UserDetailsService 인터페이스를 수단으로 사용하는 것이다.

 

그리고 이 DB에 접근해서 가져온 데이터를,

 

Authentication 객체의 사용자 정보와 비교하여 인증이 성공하면,

 

해당 객체를 생성하여(new UsernamePasswordAuthenticationToken) 정상 리턴한다.

 

간추리면 이렇다. (많이 생략)

 

 

 

AuthenticationProvider를 사용할 때,

 

PasswordEncoder와의 환상적인 콜라보로 (스프링 시큐리티 5 버전 이상은 필수)

 

if(!passwordEncoder.matches(password, user.getPassword())) {
    throw new BadCredentialsException("password error");
}

 

이렇게 비교하여 예외 던지기 놀이가 가능하다.

 

파라미터만 봐도,

 

사용자 입력 비밀번호 & DB 비밀번호 비교(matches)가 주목적이다.

 

당연히 사용자의 암호를 생성(create)하여 저장(save)할 때 인코더(PasswordEncoder)를 이용해서

 

암호를 인코딩 후 저장했다고 기대한다.

 

보통 SecurityConfig 클래스에,

@Bean
public PasswordEncoder getPasswordEncoder() {
	return new BCryptPasswordEncoder();
}

 

이런 형태로 구현된다.

 

 

 

대강의 코드는 이렇다.

package com.myproj.security;

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.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/* whether exists or not, work well */

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider{
	
	@Autowired
	private MyprojUsersService myprojUsersService;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException{
		String username = authentication.getName();
		//System.out.println("cred.=" + authentication.getCredentials());
		String password = (String)authentication.getCredentials();
		
		UsernamePasswordAuthenticationToken authToken = (UsernamePasswordAuthenticationToken) authentication; 
        
        	UserDetails user = myprojUsersService.loadUserByUsername(authToken.getName());
          
        	if(!passwordEncoder.matches(password, user.getPassword())) {
            		throw new BadCredentialsException("password error");
        	}
       
        	return new UsernamePasswordAuthenticationToken(username, password, user.getAuthorities());
		
	}
	
	@Override
    	public boolean supports(Class<?> authentication) {
        	return authentication.equals(UsernamePasswordAuthenticationToken.class);
    	}
}
Comments