Java 如何在关闭浏览器窗口时删除HttpOnly服务器端会话cookie

Java 如何在关闭浏览器窗口时删除HttpOnly服务器端会话cookie,java,typescript,cookies,spring-security,angularjs-1.7,Java,Typescript,Cookies,Spring Security,Angularjs 1.7,我需要在用户关闭浏览器窗口时关闭由JSESSIONIDcookie持有的会话。 此cookie由Spring Security在服务器端设置: @Configuration @EnableWebSecurity public class SpringSecurityConfiguration { @Configuration public static class ApplicationApiSecurityConfiguration extends WebSecurityCo

我需要在用户关闭浏览器窗口时关闭由
JSESSIONID
cookie持有的会话。 此cookie由Spring Security在服务器端设置:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration {

    @Configuration
    public static class ApplicationApiSecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(final HttpSecurity http) {
        http
                    .antMatcher("/**")
          .csrf()
          .disable() // Disable Cross Site Request Forgery Protection
          .formLogin() // Enable form based/cookie based/session based login
          .loginPage(LOGIN_PAGE) // Set our custom login page
          .and()
            .authorizeRequests()
            .antMatchers("/login", "/logout")
            .permitAll() // Allow anyone to access the login and logout page
            .anyRequest()
            .authenticated() //All other request require authentication
          .and()
            .logout()
            .deleteCookies("JSESSIONID") // Delete JSESSIONID cookie on logout
            .clearAuthentication(true) // Clean authentication on logout
            .invalidateHttpSession(true); // Invalidate Http Session on logout
        }
    }
}
在客户端,我有AngularJS 1.7和TypeScript,通过设置
@module.ts

module app.myapp {

    import IModule = angular.IModule;

    import IStateProvider = angular.ui.IStateProvider;
    import IUrlRouterProvider = angular.ui.IUrlRouterProvider;

    import LockService = lib.common.LockService;

    export class MyApp {

        static NAME = 'app.myapp';

        static module(): IModule {
            return angular.module(MyApp.NAME);
        }
    }

    angular.module(MyApp.NAME, ['ui.router'])
        .config([
            '$stateProvider', '$urlRouterProvider',
            ($stateProvider: IStateProvider, $urlRouterProvider: IUrlRouterProvider) => {

                $urlRouterProvider.when('', '/home');

                $stateProvider.state('base', {
                    url: '',
                    abstract: true,
                    template: '<ui-view/>',
                    resolve: {
                        initEventListenerForGlobalUnlock: [
                            LockService.ID,
                            (lockService: LockService) => lockService.initListenerForGlobalUnlock()
                        ]
                    }
                });

                $stateProvider.state('personalProfile', {
                    url: '/profile',
                    parent: 'base',
                    component: PersonalProfile.ID
                });
            }
        ]);
}
当前,有一个注销功能,它基于通过执行
此操作重定向页面。$window.location.href='logout'

但我想要的是在浏览器窗口关闭时通过单击[x]删除会话cookie(或者以某种方式使会话无效),这样即使用户通过在地址栏中粘贴URL返回到同一页面,也会要求他重新登录


问题在于
JSESSIONID
cookie被设置为HttpOnly,因此无法从JavaScript中删除。我不知道如何让服务器端的Spring Security使会话无效。

回答我自己的问题

我发现在浏览器窗口关闭时实现会话过期的唯一方法是对
globalUnlockHandler
onbeforeuload事件侦听器中的注销URL执行同步XHR请求

AngularJS
$http.get
可能不起作用,因为它是异步的,调用在完成之前被取消

以下是传统跨浏览器XHR对象创建的TypeScript示例:

createXMLHttpRequest(): XMLHttpRequest {
    var req: XMLHttpRequest = null;
    if (this.$window.XMLHttpRequest) {
        try {
            req = new XMLHttpRequest();
        } catch (e) { }
    } else if (this.$window.ActiveXObject) {
        try {
            req = new ActiveXObject('Msxml2.XMLHTTP'); // tslint:disable-line
        } catch (e) {
            try {
                req = new ActiveXObject('Microsoft.XMLHTTP'); // tslint:disable-line
            } catch (e) { }
        }
    } // fi
    if (!req) {
        console.warn('createXMLHttpRequest() failed');
    }
    return req;
}
然后打电话:

var xhr = new XMLHttpRequest();
if (xhr) {
    xhr.open('GET', 'http://www.domain.name/logout', false);
    try {
        xhr.send(null);
    } catch (e) {
        console.warn(e);
    }
}

请注意,XHR已被弃用,而且这种方法违反了HTTP原则,因为用户可以打开一个新的浏览器选项卡并从现有浏览器复制/粘贴URL。然后,如果第一个选项卡关闭,会话将终止,但第二个选项卡仍将打开,没有有效会话。

回答我自己的问题

我发现在浏览器窗口关闭时实现会话过期的唯一方法是对
globalUnlockHandler
onbeforeuload事件侦听器中的注销URL执行同步XHR请求

AngularJS
$http.get
可能不起作用,因为它是异步的,调用在完成之前被取消

以下是传统跨浏览器XHR对象创建的TypeScript示例:

createXMLHttpRequest(): XMLHttpRequest {
    var req: XMLHttpRequest = null;
    if (this.$window.XMLHttpRequest) {
        try {
            req = new XMLHttpRequest();
        } catch (e) { }
    } else if (this.$window.ActiveXObject) {
        try {
            req = new ActiveXObject('Msxml2.XMLHTTP'); // tslint:disable-line
        } catch (e) {
            try {
                req = new ActiveXObject('Microsoft.XMLHTTP'); // tslint:disable-line
            } catch (e) { }
        }
    } // fi
    if (!req) {
        console.warn('createXMLHttpRequest() failed');
    }
    return req;
}
然后打电话:

var xhr = new XMLHttpRequest();
if (xhr) {
    xhr.open('GET', 'http://www.domain.name/logout', false);
    try {
        xhr.send(null);
    } catch (e) {
        console.warn(e);
    }
}

请注意,XHR已被弃用,而且这种方法违反了HTTP原则,因为用户可以打开一个新的浏览器选项卡并从现有浏览器复制/粘贴URL。然后,如果第一个选项卡关闭,会话将终止,但第二个选项卡仍将在没有有效会话的情况下打开。

我有点困惑,JSESSIONID不是会话cookie吗,这意味着一旦浏览器关闭,它将被删除?可能您正在寻找类似AFAIR会话cookie的内容。重新启动浏览器后,会话cookie会暂时消失。但是,在用户注销之前,会话仍处于活动状态。浏览器窗口关闭时,JSESSION cookie不会消失。这可以通过Firefox本地存储检查器进行验证。我不知道为什么Spring在注销时在
deleteCookie()
之上有
clearAuthentication()
invalidateHttpSession()
方法。我不需要特别对JSESSION cookie做什么,我需要的是会话在窗口关闭时完全消失,不管怎样。>JSESSION cookie不会消失,只是在这里检查一下。首先,所有Firefox窗口都关闭了吗?第二,当您关闭然后重新打开时,cookie中的JSESSIONID值是否相同?第三,cookie上的expires字段是什么意思?如果它显示“会话”,那么浏览器应该在进程终止后删除它。至于您关于使会话无效的评论,您必须以某种方式将自己附加到窗口关闭事件,并对服务进行HTTP调用以注销用户。不确定Javascript是否可以做到这一点。@jzheaux由于我怀疑是Spring SessionFixationProtectionStrategy而导致JSSessionID更改。将其设置为“无”可能会起作用,但我还没有测试。在卸载事件处理期间执行对注销页面的HTTP调用也可能是一种解决方案。我明天要考试。谢谢。我有点困惑,JSESSIONID不是一个会话cookie吗,这意味着一旦浏览器关闭它就会被删除?可能您正在寻找类似AFAIR会话cookie的内容。重新启动浏览器后,会话cookie会暂时消失。但是,在用户注销之前,会话仍处于活动状态。浏览器窗口关闭时,JSESSION cookie不会消失。这可以通过Firefox本地存储检查器进行验证。我不知道为什么Spring在注销时在
deleteCookie()
之上有
clearAuthentication()
invalidateHttpSession()
方法。我不需要特别对JSESSION cookie做什么,我需要的是会话在窗口关闭时完全消失,不管怎样。>JSESSION cookie不会消失,只是在这里检查一下。首先,所有Firefox窗口都关闭了吗?第二,当您关闭然后重新打开时,cookie中的JSESSIONID值是否相同?第三,cookie上的expires字段是什么意思?如果它显示“会话”,那么浏览器应该在进程终止后删除它。至于您关于使会话无效的评论,您必须以某种方式将自己附加到窗口关闭事件,并对服务进行HTTP调用以注销用户。不确定Javascript是否可以做到这一点。@jzheaux由于我怀疑是Spring SessionFixationProtectionStrategy而导致JSSessionID更改。将其设置为“无”可能会起作用,但我还没有测试。在卸载事件处理期间执行对注销页面的HTTP调用也可能是一种解决方案。我明天要考试。谢谢