从 https 切换到 http 时登录后 spring-boot 用户会话未添加到上下文中

Posted

技术标签:

【中文标题】从 https 切换到 http 时登录后 spring-boot 用户会话未添加到上下文中【英文标题】:spring-boot user session not added to context after login when switching from https to http 【发布时间】:2016-12-15 07:23:57 【问题描述】:

我有一个 spring-boot 1.3.5.RELEASE 和 spring security 4.1.0.RELEASE 应用程序,用户在第一次输入用户名和密码后被重定向到登录页面。他们第二次输入用户名和密码时,它工作正常。

场景如下:

    用户被重定向到登录页面(使用 HTTPS)

    用户输入用户名和密码并回车

    用户再次被重定向到登录页面,就好像他没有输入用户名和密码一样

    用户再次输入用户名和密码并回车

    用户被重定向到主页 (HTTP)

每次用户尝试登录时都会发生这种情况。

编辑:当我重新启动 spring-boot 应用程序或打开新的浏览器会话(chrome 人)时,不会发生这种情况。似乎只有在退出后才会发生

我追踪到 spring 的用户会话修复,但不知道如何修复。

我的配置是什么样子的:

@Override
public void configure(HttpSecurity http) throws Exception 
    http
        .headers().disable()
        .csrf().disable()
        .formLogin()
            .loginPage("/auth/login")
            .loginProcessingUrl("/auth/login")
            .failureUrl("/auth/login-secure?loginFailed=true")
            .defaultSuccessUrl("/defaultEntry")
            .usernameParameter("username")
            .passwordParameter("password")
        .and()
        .logout()
            .logoutUrl("/auth/logout")
            .logoutSuccessUrl("/auth/logout-success")
        .deleteCookies("jsessionid", "JSESSIONID")
        .and()
        .sessionManagement().sessionFixation().none()
        .and()
        .anonymous().principal(ANONYMOUS_USER)

        .and()
        .authorizeRequests()
            .antMatchers("/websocket/**").authenticated()
            .antMatchers("/auth/login", "/auth/login-secure", "/auth/login-oauth2").permitAll()
            .antMatchers("/auth/external-logout").authenticated()
            .antMatchers("/index.jsp").permitAll()
            .antMatchers("/defaultEntry").authenticated()
            .antMatchers("/admin/**/*").hasRole("T2K_ADMIN")
            .antMatchers("/client/**/*").authenticated();

    // we set the redirect port for https for dev environment. Production environment has the connectors configured in Tomcat's server.xml
    if (Arrays.asList(environment.getActiveProfiles()).contains(SpringProfiles.DEVELOPMENT)) 
        http.portMapper()
                .http(Integer.parseInt(environment.getProperty("server.port")))
                .mapsTo(Integer.parseInt(environment.getProperty("server.https.port")));
    

    http.requiresChannel()
            .antMatchers("/auth/**").requiresSecure()
            .anyRequest().requiresInsecure();

控制器:

@Controller
public class HomeController 

    @Autowired
    private CGSUserDetails currentUser;

    @Autowired
    private Authentication authentication;

    @RequestMapping(value = "/auth/login", method = RequestMethod.GET)
    public String login() 
        return "redirect:login-secure";
    

    @RequestMapping(value = "/auth/login-secure", method = RequestMethod.GET)
    public String loginSecure() 
        if (authentication.isAuthenticated() && !ANONYMOUS_USER.equals(authentication.getName())) 
            return "redirect:/defaultEntry";
         else 
            return "auth/login"; // get /auth/login.jsp
        
    

    @RequestMapping(value = "/home", method = RequestMethod.GET)
    public String openHomePage() throws Exception 
        if (authentication.isAuthenticated() && !ANONYMOUS_USER.equals(authentication.getName())) 
            return "index";
         else 
            return "redirect:/defaultEntry";
        
    

    @RequestMapping(value = "/defaultEntry", method = RequestMethod.GET)
    public String defaultEntry() 
        if (authentication.isAuthenticated() && !ANONYMOUS_USER.equals(authentication.getName())) 
            return "redirect:/home";
         else 
            return "redirect:login";
        
    

用户和身份验证 bean:

@Bean(name = "userDetails")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserDetails userDetails() 
    return AuthenticationHolder.getUserDetails();


@Bean(name = "authentication")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public Authentication authentication() 
    return AuthenticationHolder.getAuthentication();

我在调试过程中发现的:

    在加载页面时,浏览器通过 HTTPS 重定向到 login

    在用户输入用户名和密码并回车后,浏览器尝试通过 HTTPS 加载 defaultEntry,然后通过 HTTP 重定向到 defaultEntry。 我放置了一个过滤器和一个应用程序侦听器来跟踪正在发生的事情,我看到了以下内容 登录后按回车:

onApplicationEvent - 为用户验证会话:admin,sessionId:80CDEA048679E189485FE0F4597BE2E8

(TestFilter.java:34) 访问的 URL:https://localhost:8443/auth/login;当前用户:匿名

(TestFilter.java:34) 访问的 URL:https://localhost:8443/auth/login-secure;当前用户:匿名

(TestFilter.java:34) 访问的 URL:https://localhost:8443/auth/login-strings;当前用户:匿名

    用户被重定向到通过 HTTP 登录,它重定向到通过 HTTPS 的安全登录 用户再次输入用户名和密码并回车 defaultEntry 现在直接通过 HTTP 加载(不再首先尝试通过 HTTPS)并加载主页

onApplicationEvent - 为用户验证会话:admin,sessionId:933F361668CFF01EBCC0DF88763D4DF4

(TestFilter.java:34) 访问的 URL:http://localhost:8000/defaultEntry;当前用户:CGSUserDetailsImplfirstName='admin', lastName='admin', email='admin@mycompany.com'

我也尝试更改 sessionFixation 模式和范围,但用户和授权在其他配置中不再自动装配。

我怎样才能让它第一次正确重定向到家?

【问题讨论】:

【参考方案1】:

好的,我修好了。 就我而言,问题是由注销表单引起的。

@RequestMapping(value = "/auth/logout-success", method = RequestMethod.GET)
public String logoutSuccess() 
    return "auth/logout-success";

这正在加载以下 .jsp

<head>
    <title>Logout</title>
</head>
<body>
    <script type="text/javascript">
        window.location = "login";
    </script>
</body>

我删除了这个 .jsp 并将注销映射更改为:

@RequestMapping(value = "/auth/logout-success", method = RequestMethod.GET)
public String logoutSuccess() 
    return "redirect:/defaultEntry";

【讨论】:

以上是关于从 https 切换到 http 时登录后 spring-boot 用户会话未添加到上下文中的主要内容,如果未能解决你的问题,请参考以下文章

NSURLSessionDownloadTask 从 http 切换到 https

Grails 重定向控制器从 https 切换到 http。为啥?

如何将负载均衡器从 HTTP 切换到 HTTPS?

从 ssl 移动到非 ssl 时会话未保存

如何从 HTTPS 重定向到 HTTP 而不会出现烦人的错误消息

当我们在 https 和 http 之间切换时,如何在 java springs 2.5.6 中传递/复制参数