我们有一个 Spring Security 应用程序,它主要在将用户传递到 Angular 应用程序之前通过 Thymeleaf 页面处理身份验证。目前,如果用户已经登录并尝试访问/login,则会将他们带到要填写的登录页面 - 如果他们仅访问/,那么他们将被正确重定向到我们的仪表板/主页。我们只是希望能够将/login 重定向到/对于经过身份验证的用户。
这是我们正在使用的 HttpSecurity 配置,我猜应该只需要进行简单的修改即可实现此目标:
@Override
public void configure( HttpSecurity http ) throws Exception
{
// @formatter:off
http
.cors()
.and()
.exceptionHandling()
.accessDeniedHandler( accessDeniedHandler() )
.authenticationEntryPoint( new RestAuthenticationEntryPoint() )
.and()
.authorizeRequests()
.antMatchers( "/login" ).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/login" )
.failureHandler( internalAuthFailureHandler )
.successHandler( internalAuthSuccessHandler )
.permitAll()
.and()
.logout()
.logoutUrl( "/logout" )
.logoutSuccessUrl( "/login?logout" )
.permitAll()
.and()
.csrf()
.csrfTokenRepository( CookieCsrfTokenRepository.withHttpOnlyFalse() );
// @formatter:on
}
我尝试对/login 页面使用 .not().authenticated() ,但无法弄清楚这一点,而且我不明白哪些文档应该对此有所帮助。
最佳答案
这是因为生成登录页面的过滤器高于处理 HttpSecurity 匹配器的过滤器,因此为什么使用 .not().authenticated()
或其他常规方法不起作用你。
首先,我创建了一个自定义过滤器类,我将其命名为LoginPageFilter:
class LoginPageFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (SecurityContextHolder.getContext().getAuthentication() != null
&& SecurityContextHolder.getContext().getAuthentication().isAuthenticated()
&& ((HttpServletRequest)request).getRequestURI().equals("/login")) {
System.out.println("user is authenticated but trying to access login page, redirecting to /");
((HttpServletResponse)response).sendRedirect("/");
}
chain.doFilter(request, response);
}
}
以上代码将检查当前用户是否已通过身份验证以及当前路径是否为 /login
。
如果是,那么它将把他重定向到/
。否则,继续遍历过滤器链。
之后,您需要将过滤器添加到现有过滤器链中,但无法将其添加到任何地方。它必须在 session ID 解析身份验证之后(否则,SecurityContextHolder.getContext().getAuthentication() 将始终返回 null),并且必须位于允许访问的现有过滤器之前到登录页面。
最佳候选者位于 DefaultLoginPageGenerateFilter
之前,它是生成登录页面的过滤器。
要在该位置添加自定义过滤器,您需要将其添加到 configure(HttpSecurity http)
方法的顶部:
http.addFilterBefore(new LoginPageFilter(), DefaultLoginPageGeneratingFilter.class);
在您的示例中,它将如下所示:
@Override
public void configure( HttpSecurity http ) throws Exception
{
http.addFilterBefore(new LoginPageFilter(), DefaultLoginPageGeneratingFilter.class);
// @formatter:off
http
.cors()
.and()
.exceptionHandling()
.accessDeniedHandler( accessDeniedHandler() )
.authenticationEntryPoint( new RestAuthenticationEntryPoint() )
.and()
.authorizeRequests()
.antMatchers( "/login" ).permitAll()
// ...
// @formatter:on
}
我已经上传了完整的类(class),以便您需要仔细查看:
https://gist.github.com/TwinProduction/5e2e320f5f87c009c330828c3e34a6dc
祝你好运!
更新
根据 @dur 的建议,我将 UsernamePasswordAuthenticationFilter
替换为 DefaultLoginPageGeneratingFilter
,这是更合适的候选者。
关于java - 从/登录重定向到/针对经过身份验证的用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50334528/