복붙노트

[SPRING] 대체 인증없이 다른 로그인 양식을 인증하기위한 다른 UsernamePasswordAuthToken을 사용하는 여러 AuthenticationProvider

SPRING

대체 인증없이 다른 로그인 양식을 인증하기위한 다른 UsernamePasswordAuthToken을 사용하는 여러 AuthenticationProvider

스프링 보안으로 작업하는 동안 스택 오버 플로우에서 흥미로운 스레드를 살펴 보았지만 LDAP 및 직원에 대한 직원과 다른 인증 공급자에 대해 두 명의 사용자 세트를 인증해야했습니다. 스레드는 수락 된 솔루션을 제공하여 직원과 고객을 구별하는 라디오 버튼이있는 단일 로그인 양식을 가지며 userType을 기반으로 로그인 요청을 구별하고 다른 authenticationToken (customerAuthToken / employeeAuthToken)을 설정하고 인증 요청이 진행되는 사용자 정의 인증 필터를 갖습니다. 두 가지 AuthenticationProvider 구현이 있으며 토큰을 지원하여 인증이 수행되고 결정됩니다. 이러한 방식으로 스레드는 스프링 보안이 기본적으로 제공하는 폴백 인증을 피하기 위해 흥미로운 솔루션을 제공 할 수있었습니다.

여러 진입 점을 갖도록 Spring Security 3.x 구성 스레드를 살펴보십시오.

대답은 완전히 XML 구성에 있기 때문입니다. 방금 솔루션을 Java 구성에서 사용할 수 있기를 원했습니다. 나는 그 답을 게시 할 것입니다.

이제 스프링 버전의 진화와 함께 내 질문은 내 대답 외에도 새로운 기능 / 최소 구성으로 동일한 기능을 가질 수 있습니까?

해결법

  1. ==============================

    1.이 스레드는 완전한 정보를 제공 했으므로 Java 구성 참조 코드를 게시하고 있습니다.

    이 스레드는 완전한 정보를 제공 했으므로 Java 구성 참조 코드를 게시하고 있습니다.

    여기서 나는 다음과 같은 것을 가정하고있다. 1. 사용자와 관리자는 두 명의 사용자 집합입니다. 메모리 인증에서 두 가지 모두를 사용하는 것이 간편합니다.    -userType이 User 인 경우 사용자 자격 증명 만 작동합니다.    -userType이 Admin 인 경우 관리자 자격 증명 만 작동합니다.    -다른 권한을 가진 동일한 애플리케이션 인터페이스를 제공 할 수 있어야합니다.

    그리고 코드 내 github 저장소에서 작업 코드를 다운로드 할 수 있습니다 CustomAuthenticationFilter

    @Component
    public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter
    {
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException
        {
            UsernamePasswordAuthenticationToken authToken = null;
    
            if ("user".equals(request.getParameter("userType"))) 
            {
                authToken = new UserUsernamePasswordAuthenticationToken(request.getParameter("userName"), request.getParameter("password"));
            }
            else 
            {
                authToken = new AdminUsernamePasswordAuthenticationToken(request.getParameter("userName"), request.getParameter("password"));
            }
    
            setDetails(request, authToken);
    
            return super.getAuthenticationManager().authenticate(authToken);
        }
    }
    

    CustomAuthentictionTokens

    public class AdminUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken
    {   
        public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials)
        {
            super(principal, credentials);
        }
    
        public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials,
                Collection<? extends GrantedAuthority> authorities)
        {
            super(principal, credentials, authorities);
        }
    }
    
    public class UserUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken
    {
        public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials)
        {
            super(principal, credentials);
        }
    
        public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials,
                Collection<? extends GrantedAuthority> authorities)
        {
            super(principal, credentials, authorities);
        }}
    

    CustomAuthenticationProvider-관리자 용

    @Component
    public class AdminCustomAuthenticationProvider implements AuthenticationProvider
    {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException
        {
            String username = authentication.getName();
            String password = authentication.getCredentials().toString();
    
            if (username.equals("admin") && password.equals("admin@123#"))
            {
                List<GrantedAuthority> authorityList = new ArrayList<>();
                GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ADMIN");
                authorityList.add(authority);
    
                return new UserUsernamePasswordAuthenticationToken(username, password, authorityList);
            }
            return null;
        }
    
        @Override
        public boolean supports(Class<?> authentication)
        {
            return authentication.equals(AdminUsernamePasswordAuthenticationToken.class);
        }
    }
    

    CustomAuthenticationProvider-사용자 용

    @Component
    public class UserCustomAuthenticationProvider implements AuthenticationProvider
    {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException
        {
    
            String username = authentication.getName();
            String password = authentication.getCredentials().toString();
    
            if (username.equals("user") && password.equals("user@123#"))
            {
                List<GrantedAuthority> authorityList = new ArrayList<>();
                GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
                authorityList.add(authority);
    
                return new UserUsernamePasswordAuthenticationToken(username, password, authorityList);
            }
            return null;
        }
    
        @Override
        public boolean supports(Class<?> authentication)
        {
            return authentication.equals(UserUsernamePasswordAuthenticationToken.class);
        }
    }
    

    CustomFilter에 필요한 CustomHandlers

    @Component
    public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler
    {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException
        {
            response.sendRedirect(request.getContextPath() + "/login?error=true");
        }   
    }
    
    @Component
    public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler
    {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
        {
            HttpSession session = request.getSession();
            if (session != null)
            {
                session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
            }
            response.sendRedirect(request.getContextPath() + "/app/user/dashboard");
        }
    }
    

    그리고 마지막으로 SpringSecurityConfiguration

    @Configuration
    @EnableWebSecurity
    public class SpringSecurityConfig extends WebSecurityConfigurerAdapter 
    {
        @Autowired
        DataSource dataSource;
    
        @Autowired
        private AdminCustomAuthenticationProvider adminCustomAuthenticationProvider;
    
        @Autowired
        private UserCustomAuthenticationProvider userCustomAuthenticationProvider;
    
        @Autowired
        private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
    
        @Autowired
        private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception
        {
            auth.authenticationProvider(adminCustomAuthenticationProvider);
            auth.authenticationProvider(userCustomAuthenticationProvider);
        }
    
        @Bean
        public MyAuthenticationFilter myAuthenticationFilter() throws Exception
        {
            MyAuthenticationFilter authenticationFilter = new MyAuthenticationFilter();
    
            authenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
            authenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
            authenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
            authenticationFilter.setAuthenticationManager(authenticationManagerBean());
    
            return authenticationFilter;
        }
    
        @Override
        protected void configure(final HttpSecurity http) throws Exception
        {
            http
            .addFilterBefore(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/resources/**", "/", "/login")
                    .permitAll()
                .antMatchers("/config/*", "/app/admin/*")
                    .hasRole("ADMIN")
                .antMatchers("/app/user/*")
                    .hasAnyRole("ADMIN", "USER")
                .antMatchers("/api/**")
                    .hasRole("APIUSER")
            .and().exceptionHandling()
                .accessDeniedPage("/403")
            .and().logout()
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .invalidateHttpSession(true);
    
            http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
        }
    }
    

    대체 인증없이 다중 인증 구성을 이해하는 데 도움이되기를 바랍니다.

  2. from https://stackoverflow.com/questions/57881749/multiple-authenticationprovider-with-different-usernamepasswordauthtoken-to-auth by cc-by-sa and MIT license