UsernamePasswordAuthenticationFilter in spring Security doesn't get invoke
我想在登录时传递JSON而不是使用参数。所以我要做的是创建一个过滤器,但是,奇怪的是,过滤器本身根本不会被调用(或者基本上是当我尝试时登录,通过传递请求,完全忽略我的过滤器)。该请求直接进入我的AuthenticationHandler。我已经浏览了许多文章,但仍然不知道为什么会发生这种情况,特别是当我在Java中复制相同的代码结构但它按预期的方式完美工作时...
我错过了明显的事情吗?这是UsernamePasswordAuthenticationFilter和我的安全性配置。我的Java版本工作正常,但我的Kotlin版本完全忽略了过滤器。
它也不返回404,它返回我的AuthenticationFailureHandler。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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中的安全性配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | 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版本略有不同,但我认为它应该具有相同的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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中的安全性配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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
我只是将这个问题留在这里,以防万一有人像我一样遇到这个愚蠢的问题。
1 2 3 4 5 6 7 8 | 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 } |