java - 从/登录重定向到/针对经过身份验证的用户

标签 java spring spring-security spring-java-config

我们有一个 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/

相关文章:

java - 部署 Spring Boot 应用程序时 Heroku 错误代码 H10

spring - 将Spring集成依赖项添加到项目中时,LocationAwareLogger异常

Spring | hibernate |使用 AspectJ 进行事务管理

java - 遵循 Grails Spring Security Core 教程时出现 "No transaction is in progress"错误

java - 就线程或不同请求而言,Spring 的 SecurityContext 行为是什么?

java - 标准 CodeCacheManager JMX bean 是什么?

java - 在您的配置中定义 'bean' 、 "Consider defining a bean named 'EntityManagerFactory' 时遇到麻烦”

java - 更新表数据标签和Html :hidden field values using Ajax call

java - 具有多个可选参数的 Spring Data MongoDB AND/OR 查询

java - 如何在 Spring Security 中强制重新验证凭据?