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,我已经beforeunload
通过设置来捕获事件@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
});
}
]);
}
然后对于我的 LockService 实现:
module lib.common {
import IWindowService = angular.IWindowService;
import IRootScopeService = angular.IRootScopeService;
export class LockService {
static ID = 'lockService';
static $inject: string[] = ['$window', '$rootScope'];
constructor(
private readonly $window: IWindowService,
private readonly $rootScope: IRootScopeService
) { }
private readonly globalUnlockHandler = (ev: BeforeUnloadEvent) => {
// This does not work with HttpOnly cookies
document.cookie = 'JSESSIONID=;path=/;domain=' + window.location.hostname + ';expires=Thu, 01 Jan 1970 00:00:01 GMT';
this.$rootScope.$digest();
return null;
}
/**
* This is called upon app initialisation,
* an event listener for browser close is registered,
* which will use an API call to unlock all locked sections before exiting
*/
initListenerForGlobalUnlock(): void {
this.$window.addEventListener('beforeunload', this.globalUnlockHandler);
}
}
LibCommon.module().service(LockService.ID, LockService);
}
目前,有一个基于重定向页面的注销功能this.$window.location.href = 'logout'
但是我想要的是在通过单击[x]关闭浏览器窗口时删除会话 cookie(或者以某种方式使会话无效),这样即使用户通过在地址栏中粘贴 URL 回到同一页面,他被要求重新登录。
问题是JSESSIONID
cookie 设置为 HttpOnly,因此无法从 JavaScript 中删除。而且我不知道如何告诉服务器端的 Spring Security 使会话无效。