spring Security中的UsernamePasswordAuthenticationFilter不';得不到调用

spring Security中的UsernamePasswordAuthenticationFilter不';得不到调用,spring,spring-security,kotlin,Spring,Spring Security,Kotlin,我想在登录时传入JSON而不是使用params。所以我要做的是创建一个过滤器,然而,奇怪的是过滤器本身根本没有得到调用(或者基本上当我尝试登录时,请求通过它,完全忽略我的过滤器)。请求直接转到我的AuthenticationHandler。我已经读了很多文章,但我仍然不知道为什么会发生这种情况,特别是当我在Java中复制相同的代码结构时,但它完全按照预期工作 我错过了什么明显的东西吗?这是用户名PasswordAuthenticationFilter和我的安全配置。我的Java版本工作正常,但我

我想在登录时传入JSON而不是使用params。所以我要做的是创建一个过滤器,然而,奇怪的是过滤器本身根本没有得到调用(或者基本上当我尝试登录时,请求通过它,完全忽略我的过滤器)。请求直接转到我的AuthenticationHandler。我已经读了很多文章,但我仍然不知道为什么会发生这种情况,特别是当我在Java中复制相同的代码结构时,但它完全按照预期工作

我错过了什么明显的东西吗?这是用户名PasswordAuthenticationFilter和我的安全配置。我的Java版本工作正常,但我的Kotlin版本完全忽略了过滤器

它也不会返回404,而是返回我的AuthenticationFailureHandler

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import lombok.Getter
import org.apache.commons.io.IOUtils
import org.springframework.http.HttpMethod
import org.springframework.security.authentication.AuthenticationServiceException
import org.springframework.security.authentication.InternalAuthenticationServiceException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.io.IOException
import java.nio.charset.Charset

class JsonLoginFilter : UsernamePasswordAuthenticationFilter() {

     @Throws(AuthenticationException::class)
     override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse?): Authentication {
         if (!HttpMethod.POST.matches(request.method)) {
            throw AuthenticationServiceException("Authentication method not supported: " + request.method)
         }

         val payload: String
         try {
              payload = IOUtils.toString(request.inputStream, Charset.defaultCharset())
              val auth = ObjectMapper().readValue(payload, JsonAuthenticationParser::class.java)
             // println(auth.username)
             // println(auth.password)
              val authRequest = UsernamePasswordAuthenticationToken(auth.username, auth.password)
              return this.authenticationManager.authenticate(authRequest)
         } catch (e: IOException) {
              throw InternalAuthenticationServiceException("Could not parse authentication payload")
         }

    }

    @Getter
    data class JsonAuthenticationParser @JsonCreator
    constructor(@param:JsonProperty("username")
                 val username: String,
                @param:JsonProperty("password")
                 val password: String)
    }
我在Kotlin中的安全配置

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
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.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler

@EnableWebSecurity
class WebSecurity: WebSecurityConfigurerAdapter() {

    @Autowired
    private lateinit var entryConfig: EntryConfig

    @Autowired
    private lateinit var failAuth: FailAuthentication

    @Autowired
    private lateinit var successAuthentication: SuccessAuthentication

    @Autowired
    private lateinit var authenticationHandler: AuthenticationHandler

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {

        http
                .authorizeRequests()
                .antMatchers("/api/v1/traveller/add","/api/v1/symptoms","/api/v1/flights","/api/v1/user/login","/api/v1/user/logout").permitAll()
                .antMatchers("/api/v1/user/**","/api/v1/traveller/**").hasRole("ADMIN")
                .antMatchers("/**").authenticated()
                .and()
                .addFilterAt(authenFilter(), UsernamePasswordAuthenticationFilter::class.java)
                .formLogin().loginProcessingUrl("/api/v1/user/login")
                .successHandler(successAuthentication).failureHandler(failAuth)
                .and()
                .exceptionHandling().authenticationEntryPoint(entryConfig)
                .and()
                .cors()
                .and()
                .logout().logoutUrl("/api/v1/user/logout")
                .clearAuthentication(true)
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .logoutSuccessHandler(HttpStatusReturningLogoutSuccessHandler())
                .permitAll()


        //

        http
                .csrf()
                .disable()
    }


    @Throws(Exception::class)
    override fun configure(auth: AuthenticationManagerBuilder) {
        auth.authenticationProvider(authenticationHandler)
    }

    @Bean
    @Throws(Exception::class)
    fun authenFilter(): JsonLoginFilter {
        var filter : JsonLoginFilter = JsonLoginFilter()
        filter.setAuthenticationManager(authenticationManagerBean())
        filter.setAuthenticationSuccessHandler(successAuthentication)
        filter.setAuthenticationFailureHandler(failAuth)
        return filter
    }


    @Bean
    fun passwordEncoder(): BCryptPasswordEncoder {
        return BCryptPasswordEncoder()
    }

}
我的Java版本略有不同,但我相信它应该具有相同的结构

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;

public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println("hello");
        if (! HttpMethod.POST.matches(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String payload;
        try {
            payload = IOUtils.toString(request.getInputStream(), Charset.defaultCharset());
            JsonAuthenticationParser auth = new ObjectMapper().readValue(payload, JsonAuthenticationParser.class);
            System.out.println(auth.username);
            System.out.println(auth.password);
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(auth.username, auth.password);

            return this.getAuthenticationManager().authenticate(authRequest);
        } catch (IOException e) {
            throw new InternalAuthenticationServiceException("Could not parse authentication payload");
        }
    }

    @Getter
    static class JsonAuthenticationParser {
        private final String username;
        private final String password;

        @JsonCreator
        public JsonAuthenticationParser(@JsonProperty("username") String username, @JsonProperty("password") String password) {
            this.username = username;
            this.password = password;
        }
    }
}
Java中的安全配置

import hard.string.security.AuthenticationHandler;
import hard.string.security.EntryConfig;
import hard.string.security.FailAuthhentication;
import hard.string.security.SuccessAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    private EntryConfig entryConfig;

    @Autowired
    private FailAuthhentication failAuth;

    @Autowired
    private SuccessAuthentication successAuthentication;

    @Autowired
    private AuthenticationHandler authenticationHandler;

    @Bean
    public JsonAuthenticationFilter authenticationFilter() throws Exception {
        JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
//        filter.setContinueChainBeforeSuccessfulAuthentication(true);
        filter.setAuthenticationSuccessHandler(successAuthentication);
        filter.setAuthenticationFailureHandler(failAuth);
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http://stackoverflow.com/questions/19500332/spring-security-and-json-authentication

        http
                .authorizeRequests()
                .antMatchers("/login", "/logout", "/register",
                        "/debug/**").permitAll()
                .antMatchers("/**").authenticated()
                .and()
                .addFilterAt(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .formLogin().loginProcessingUrl("/login")
                .successHandler(successAuthentication).failureHandler(failAuth)
                .and()
                .exceptionHandling().authenticationEntryPoint(entryConfig)
                .and()
                .cors()
                .and()
                .logout().logoutUrl("/logout")
                .clearAuthentication(true)
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
                .permitAll();


        //

        http
                .csrf()
                .disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationHandler);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

感谢您的帮助

好的,在花了几天的时间找到bug之后。我发现过滤器不会自动链接到loginProcessingUrl。您需要指定要在哪个url上执行筛选,否则它将仅将筛选应用于localhost:xxxx/login

我只想把这个问题留在这里,以防有人碰到像我这样的愚蠢问题

fun authenFilter(): JsonLoginFilter {
        var filter : JsonLoginFilter = JsonLoginFilter()
        filter.setAuthenticationManager(authenticationManagerBean())
        filter.setAuthenticationSuccessHandler(successAuthentication)
        filter.setAuthenticationFailureHandler(failAuth)
        filter.setFilterProcessesUrl("/api/v1/user/login") //HERE
        return filter
    }