简体   繁体   中英

Authentication Filter Works in Spring Boot, But Not In Spring Web MVC

I'm working on a project that will that requires for users to be authenticated by a proxy on the.network. Username will be provided in a request header to my app.

Spring 5 is being used to handle requests and security.

The AbstractAuthenticationProcessingFilter has been extended with my own custom filter to grab the necessary header info.

A prototype was written using Spring Boot and it was successful.

In the Spring Web MVC version, the filter is loaded, but is not triggered.

The goal is for every page in my app to require authentication. For testing purposes the 'index' page is public, and the 'blogs' page requires elevated privilege.

Why does it work in a Spring Boot project (v2.6.1), but not in Spring Web MVC (5.x)?

Any help is appreciated.

Prototype Source Code on GitHub

And some of relevant bits of code are shown below:

WebSecurityConfig.java

package org.westwood.mvc.config;

import javax.servlet.Filter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.westwood.mvc.security.CustomAuthenticationProcessingFilter;
import org.westwood.mvc.security.CustomAuthenticationProvider;
import org.westwood.mvc.security.CustomUserDetailsService;

 
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
    private CustomAuthenticationProvider customAuthenticationProvider = new CustomAuthenticationProvider();
    
    
    @Bean
    public UserDetailsService userDetailsService() {
        return new CustomUserDetailsService();
    }
    
    
    @Bean
    public CustomAuthenticationProvider authenticationProvider() {
        
        if (customAuthenticationProvider == null) {
            customAuthenticationProvider = new CustomAuthenticationProvider();
        }
        
        if (customAuthenticationProvider.userDetailsServiceIsNull()) {
            customAuthenticationProvider.setUserDetailsService(userDetailsService());
        }
        
        return customAuthenticationProvider;
    }
 
    
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic().disable()
            .csrf().disable()
            .formLogin().disable()
            .logout().disable()
            .authenticationProvider(authenticationProvider())
            .addFilterBefore(getFilter(), UsernamePasswordAuthenticationFilter.class).authorizeRequests()
            .antMatchers("/blogs").hasAuthority("ADMIN")
            .anyRequest().permitAll();

    }

    
    private RequestMatcher getRequestMatchers() {
        return new OrRequestMatcher(new AntPathRequestMatcher("/**"));
    }
    
    
    private Filter getFilter() throws Exception {
        return new CustomAuthenticationProcessingFilter(getRequestMatchers(), authenticationManager());
    }
    
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }
    
}

CustomAuthenticationProcessingFilter.java

package org.westwood.mvc.security;

import java.io.IOException;


import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.util.matcher.RequestMatcher;

public class CustomAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    public CustomAuthenticationProcessingFilter(RequestMatcher requiresAuthenticationRequestMatcher, 
            AuthenticationManager authenticationManager) {
        super(requiresAuthenticationRequestMatcher);
        setAuthenticationManager(authenticationManager);
    }

    
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        
        // extract user name from request
        String header = request.getHeader("REMOTE_USER");
        
        // hard code for testing
        header = "john-smith@gmail.com";
        
        // create a token object to pass to authentication provider
        PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(header, null);
        return getAuthenticationManager().authenticate(token);
    }
    
    
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, 
            FilterChain chain, Authentication authResult) throws IOException, ServletException {
        
        // save user principle in security context
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request, response);
    }
    
}

Spring Boot is what is picking up the Spring Security Filter Chain and registering it with the container. Without Spring Boot, you need to register it yourself.

The simplest way to do this is to use Spring Security's AbstractSecurityWebApplicationInitializer like so:

public class SpringSecurityFilterChainInitializer 
    extends AbstractSecurityWebApplicationInitializer {
}

AbstractSecurityWebApplicationInitializer#onStartup registers the Spring Security filter chain for you. Tomcat will pick up this class just like it picks up the WebInitializer in your project.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM