Spring security SpringBoot用户名PasswordAuthenticationFilter问题
我正在扩展Spring security SpringBoot用户名PasswordAuthenticationFilter问题,spring-security,spring-boot,Spring Security,Spring Boot,我正在扩展UsernamePasswordAuthenticationFilter,以便添加自定义字段以将它们保存到会话中 public class AuthFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse respon
UsernamePasswordAuthenticationFilter
,以便添加自定义字段以将它们保存到会话中
public class AuthFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
//String dbValue = request.getParameter("dbParam");
//request.getSession().setAttribute("dbValue", dbValue);
System.out.println("attempting to authentificate");
while (request.getAttributeNames().hasMoreElements()) {
String e = (String) request.getAttributeNames().nextElement();
System.out.println("param name : " + e + " and param value : " + request.getAttribute(e));
}
return super.attemptAuthentication(request, response);
}
}
还有我的网站安全配置
@Configuration
@EnableWebMvcSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
throws Exception {
AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
customUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return customUsernamePasswordAuthenticationFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().accessDeniedPage("/403").and()
.authorizeRequests().antMatchers("/login", "/public/**").permitAll()
.antMatchers("/users/**").hasAuthority("ADMIN")
.anyRequest()
.authenticated().and().formLogin().loginPage("/login")
.defaultSuccessUrl("/index").permitAll().and().logout()
.permitAll();
http.sessionManagement().maximumSessions(1)
.expiredUrl("/login?expired").and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false)
.userDetailsService(userDetailsService);
}
将筛选器:“customUsernamePasswordAuthenticationFilter”映射到:[/*] 因此,我可以确定过滤器是否正确添加,但我永远无法打印出其中的内容,因此在身份验证期间不会调用它 我使用Thymeleaf,没有xml配置 正如@M.Deinum所建议的,
我将我的
UsernamePasswordAuthenticationFilter
更改为AbstractAuthenticationProcessingFilter
,名为super(新的AntPathRequestMatcher(“/login”,“POST”);
将
addFilterAfter
更改为addFilterBefore
,并添加了一点代码,成功了 假设您使用的是最新的Spring Boot(1.2.3),那么您使用的是Spring Security 3.2.7。此版本将映射到/j\u Spring\u Security\u check
。但是,当使用基于java的配置时,会将其更改为/login
您的仍映射到旧URL。要修复此问题,请添加一个默认的无参数构造函数,该构造函数调用超级构造函数,该构造函数接受一个请求匹配器。这样做的缺点是,如果您仍然需要(或想要扩展)UsernamePasswordAuthenticationFilter的功能,则必须复制它
public AuthFilter() {
super(new AntPathRequestMatcher("/login","POST"));
}
另一个解决方案是仍然扩展
usernamespasswordauthenticationfilter
并从那里调用setrequireauthenticationrequestmatcher
public AuthFilter() {
super();
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
}
或者从工厂方法调用该方法
@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
throws Exception {
AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
customUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
customUsernamePasswordAuthenticationFilter
.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
return customUsernamePasswordAuthenticationFilter;
}
您的配置还有另一个问题,您的筛选器将永远不会执行,因为它是在默认的
UsernamePasswordAuthenticationFilter
之后执行的,并且身份验证已经发生,您的筛选器将永远不会执行。确保它在默认筛选器之前执行
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
...
}
为了使自定义UsernamePasswordAuthenticationFilter实现正常工作,请将.loginProcessingUrl(“/dologin”)添加到 WebSecurity配置,此处“/dologin”是html表单元素的操作属性值:
@Override
//@Order(Ordered.HIGHEST_PRECEDENCE)
public void configure(HttpSecurity http) throws Exception { // @formatter:off
http
...
...
.formLogin().loginPage("/login")
--> .loginProcessingUrl("/dologin") <-- add here
...
--> .addFilterBefore(new AuthFilter(authenticationManagerBean()),UsernamePasswordAuthenticationFilter.class)
}
@覆盖
//@顺序(有序。最高优先级)
public void configure(HttpSecurity http)引发异常{/@formatter:off
http
...
...
.formLogin().login页面(“/login”)
-->.loginProcessingUrl(“/dologin”).addFilterBefore(新建AuthFilter(authenticationManagerBean()),UsernamePasswordAuthenticationFilter.class)
}
下一步是提供自定义UsernamePasswordAuthenticationFilter实现:
public class AuthFilter extends UsernamePasswordAuthenticationFilter {
AuthenticationManager authenticationManager;
private boolean continueChainBeforeSuccessfulAuthentication = false;
public AuthFilter( AuthenticationManager authenticationManager){
this.authenticationManager = authenticationManager;
//idk why I have to do this, otherwise it's null
super.setAuthenticationManager(authenticationManager);
}
public AuthFilter() {}
private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
//path to which this filter will intercept
RequestMatcher customFilterUrl = new AntPathRequestMatcher("/dologin"); <--
//dofilter method is copied from AbstractAuthenticationProcessingFilter
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
//if no match then go to next filter
if (!customFilterUrl.matches(request)) {
chain.doFilter(request, response);
} else {
Authentication authResult;
try {
authResult = this.attemptAuthentication(request, response);
if (authResult == null) {
return;
}
this.sessionStrategy.onAuthentication(authResult, request, response);
} catch (InternalAuthenticationServiceException var8) {
this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
this.unsuccessfulAuthentication(request, response, var8);
return;
} catch (AuthenticationException var9) {
this.unsuccessfulAuthentication(request, response, var9);
return;
}
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authResult);
}
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response)
throws AuthenticationException {
System.out.println("Your prints"); <--
return super.attemptAuthentication(request,response);
}
}
公共类AuthFilter扩展了UsernamePasswordAuthenticationFilter{
AuthenticationManager AuthenticationManager;
private boolean ContinueChaineBefore SuccessfulAuthentication=false;
公共AuthFilter(AuthenticationManager AuthenticationManager){
this.authenticationManager=authenticationManager;
//idk为什么我必须这样做,否则它是空的
super.setAuthenticationManager(authenticationManager);
}
公共AuthFilter(){}
private SessionAuthenticationStrategy sessionStrategy=新的NullAuthenticatedSessionStrategy();
//此筛选器将截取的路径
RequestMatcher customFilterUrl=新的AntPathRequestMatcher(“/dologin”);没有,因为身份验证已经发生,所以无需再做任何事情。将其添加到用户名密码身份验证筛选器
之前,而不是之后。尝试了它,同样的问题。您可能还希望避免将其注册为@Bean
,因为它现在也被添加到普通筛选器链而不是spring安全链。Sp默认情况下,ring Boot将所有定义的@Bean
过滤器注册为过滤器,您只想将它们添加到Spring安全过滤器链中。我去掉了Bean注释,它已注册,但在身份验证期间仍然没有调用,因为我看不到我的打印。实际上没有,它没有,它获得了管理的版本这取决于Spring Boot版本。假设您使用的是最新的Spring Boot(1.2.3)您可能正在使用Spring Security 3.2.7。此版本将用户名密码身份验证筛选器
映射到/j\u Spring\u Security\u check
,但是,当使用java配置时,默认配置将更改为/login
。但是,您的用户名密码身份验证筛选器仍映射到旧URL。创建一个调用super的默认构造函数(新的AntPathRequestMatcher(“/login”,“POST”))
。UsernamePasswordAuthenticationFilter没有带参数的super,这就是我后来扩展另一个类的原因。问题是您的筛选器现在没有登录功能,因为这是特定于UsernamePasswordAuthenticationFilter
的。我修改了答案,以包含两个其他可能的解决方案。。。