ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Security에 대한 이해]인증 공급자 (Authentication Provider)(UserDetailsService,UserDetails,GrantedAuthority,UserDetailsManager) - 2
    Spring/Spring Security 2023. 2. 17. 09:18
    728x90
    반응형

     

     

    Authentication Provider (인증 공급자) 역할


     

    @Component
    public class CustomAuthenticationProvider
    [CA]implements AuthenticationProvider {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
       		 // authentication logic here
        }
        @Override
        public boolean supports(Class<?> authenticationType) {
        // type of the Authentication implementation here
        }
    }

     

    UserDetailsService,passwordencode및 Authentication객체를 전달받아  

    인증 로직을 구현하다.

     

     

    인증로직(authenticate) 구현 예제

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName(); #A
        String password = String.valueOf(
        authentication.getCredentials());
        if ("john".equals(username) && "12345".equals(password)) {
            return new UsernamePasswordAuthenticationToken(
                    username,
                    password,
            		Arrays.asList());
        } else {
        throw new AuthenticationCredentialsNotFoundException("Error!");
        }
    }

     

    위코드에서 Authentication 객체는  클라이언트에서 받은 유저,패스워드를 Authentication Filter 에서 Authentication 객체로 만들어서 AuthenticationManager -> AuthenticationProvider로 전달된다.

     

     

    ※UserDetailsService인터페이스를 구현(재정의)하지 않으면 passwordEncode는 기본 인증흐름을 따른다. 그러나 UserDetailsService인터페이스를 구현(재정의)하게 된다면 반드시 passwordEncode를 명시해야한다.

     

    처음 spring boot security에서 자동 구성된 UserDetailsService를 활용하면 , 콘솔에 유저 패스워드가 나오며

     

    curl -n user:password url 요청하면 잘작동 하는것을 볼수있다.

     

    Authentication Provider UserDetailsService 커스텀


    기본 UserDetailsService를 사용하는 경우 PasswordEncoder도 자동으로 구성된다. 하지만 UserDetailsService를 재정의하면 PasswordEncoder도 선언해야 한다.

     

    일단 위에서 설명한바로 UserDetailsService를 커스텀하려면  bean으로 UserDetailsService를 구성해야한다.

     

    디테일한 요소를 알기위해서 이미 구현해놓은 InMemoryUserDetailsManager를 이용하여 UserDetailsService를 bean으로 돌려주자

     

    @Configuration
    public class ProjectConfig {
    	
        @Bean
        UserDetailsService userDetailsService(){
        	return new InMemoryUserDetailsManager();
        }
    
    }

     

     

    위와같이 생성하고 실행시키면 콘솔에 유저 password가 생성되지 않는것을 볼수있고,더이상은 인증이 안되서 기존 url이 401 및 아래와같은 에러가 발생할것이다.

     

    java.lang.IllegalArgumentException:
    There is no PasswordEncoder mapped for the id "null"
    at
    org.springframework.security.crypto.password
    [CA].DelegatingPasswordEncoder$
    [CA]UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:289) ~[spring-security-crypto-6.0.0.jar:6.0.0]
    at org.springframework.security.crypto.password
    [CA].DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.j

     

    왜 그럴까? 여기에는 두가지 이유가있는데

    1. 더이상 유저정보를 확인하는곳이 없음.

    2. passowrdEncoder를 가지고있지 않음.

     

     위 두가지 문제를 해결해보자

     

    UserDetails - 유저정보

    1. 유저정보를 생성해주자

     

    @Configuration
    public class ProjectConfig {
    	
        @Bean
        UserDetailsService userDetailsService(){
        	UserDetails user = user.withUsername("homi")
            						.password("1234")
                                    .authorities("read")
                                    .build();
        	return new InMemoryUserDetailsManager(user);
        }
    
    }

     

    이제 curl -n homi:1234 url 로 명령어를 쳐보면 잘될줄알았는데 passwordEncoder가 없다고 에러가 뜰것이다.

     

    구성에서 passwordEncoder를 bean로 구성해보자

     

    @Bean
    PasswordEncoder passwordEncoder(){
    	return NoOpPasswordEncoder.getInstance();
    }

     

    이제 다시 curl로 homi:1234 url로 전송해보면 잘작동하는것을 알수있다.

     

    * 사용자 인증 구현

    Spring Security는 사용자의 권한,인증등을 확인하기 위해 여러가지 인터페이스를 제공하며, 현재 앱에 특성을 잘녹여 커스텀 인증을 구현할수 있다. 만약 커스텀으로 구현하지 않으면 기본 설정으로 자동 구현된다.

     

     

     

     

     

    1. 사용자 세부 정보 서비스

     

     

    1-1 UserDetailsService Interface

    public interface UserDetailsService {
        UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
    }

     

     

    'loadUserByUsername' 메소드를 이용하여 사용자 세부 정보를 가져온다. 위 메소드는 AuthincationProvider 구현체에서 사용한다. 여기서 알아둘것은 오직 '사용자' 정보만 가져온다는것이다. 이 interface의 역할은 딱 그정도까지이고 암호 확인 및 신원을 확인하는 로직이 들어가면 안된다. 

     

     

    기본구성에 대해 잘모르면 아래 링크를 통해 숙지하고 오길 바란다.

     

    https://hipdizzy.tistory.com/136

     

    [Spring Security에 대한 이해] 기본 구성 - 1

    1.Spring Security 기본 동작 구성 - 기본적으로 Spring Security는 위와같은 구성으로 동작한다. 각각에 대한 요소에 대한 설명은 아래와 같다. 인증 필터 : 인증 요청을 인증 관리자에 위임하고 , 응답을

    hipdizzy.tistory.com

     

     

    1-3 UserDetails Interface

    public interface UserDetails extends Serializable {
    	/**
          앱 사용자가 수행할 수있는 작업을 함수형 인터페이스로 저장 
        */
        Collection<? extends GrantedAuthority> getAuthorities();
    
        String getPassword();// 사용자 자격 증명을 반환하는 메서드
    
        String getUsername();// 사용자 자격 증명을 반환하는 메서드
    	
        
        /**
        사용자 계정을 필요에 따라 활성화,비활성화 하는 메서드
        */
        boolean isAccountNonExpired();//계정 만료
    
        boolean isAccountNonLocked();//계정 잠금
    
        boolean isCredentialsNonExpired();//자격 증명 만료
    
        boolean isEnabled();//계정 비활성화
    }

    위 인터페이스는 사용자를 기술한다. userdetails를 이용하여 아래와 같은 4가지를 작업을 할수있다.

    1. 계정 만료

    2. 계정 잠금

    3. 자격 증명 만료

    4. 계정 비활성화

     

     

    1-3 GrantedAuthority Interface

     

    스프링 스큐리티는 GrantedAuthority 인터페이스로 권한을 나타낸다.

    public interface GrantedAuthority extends Serializable {
        String getAuthority();
    }

     

     

    1-4 UserDetailsManager Interface

     

    public interface UserDetailsManager extends UserDetailsService {
        void createUser(UserDetails var1);
    
        void updateUser(UserDetails var1);
    
        void deleteUser(String var1);
    
        void changePassword(String var1, String var2);
    
        boolean userExists(String var1);
    }

    위 인터페이스는 UserDetailsService 계약을 확장하고 메서드를 추가한다.

    일반적으로 애플리케이션은 사용자를 관리하는 기능이 필요하며 추가,삭제,수정등이 필요한대 이때 시큐리티에 정의된 더 구체적인 인터페이스인 위를 구현하여 사용한다.

     

    728x90
    반응형
Designed by Tistory.