spring - spring Security 中的 UsernamePasswordAuthenticationFilter 没有被调用

标签 spring spring-security kotlin

我想在登录时传递 JSON 而不是使用参数。所以我所做的是创建一个过滤器,但是,奇怪的是过滤器本身根本没有被调用(或者基本上当我尝试登录后,请求绕过它,完全忽略我的过滤器)。该请求直接进入我的 AuthenticationHandler。我已经阅读了很多帖子,但我仍然不知道为什么会发生这种情况,特别是当我在 Java 中复制相同的代码结构但它按预期完美运行时......

我错过了一些明显的事情吗?这是 UsernamePasswordAuthenticationFilter 和我的安全配置。我的 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();
    }

}

感谢您的帮助

最佳答案

好的,花了几天时间才找到这个错误。我发现过滤器不会自动与loginProcessingUrl 链接。您需要指定要对其进行过滤的网址,否则它将仅将过滤器应用于 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
    }

关于spring - spring Security 中的 UsernamePasswordAuthenticationFilter 没有被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51529371/

相关文章:

java - 如何在单击链接时将java对象从jsp传递到spring Controller

java - 在 Spring Boot 应用程序中对 @Value 注释字段实现约束

java - 在 Spring 中使用 Cookie 对 Restful 服务进行身份验证

java - Android Room 实体 boolean 值与 DAO : Kotlin vs Java

java - Spring:HandlerMethodArgumentResolved 不适用于自定义注释参数

java - 无法将 JSP 项目作为动态 Web 项目导入 Eclipse

java - 在 Spring Security 登录期间设置 Grails/Spring Locale - 如何?

Spring security antMatcher 没有按预期工作

java - ARCore – 使用给定坐标实时增强图像

java - RxJava2 中 onBackPressureBuffer 的行为是什么