Vaadin 14.2:使用BeforeLeaveListener拦截注销(使会话无效)
在my Vaadin 14.2.0应用程序中,有一个BeforeLeaveListener,用于在输入脏时显示确认对话框(=输入字段中有未保存的更改)以取消(或有意继续)导航:Vaadin 14.2:使用BeforeLeaveListener拦截注销(使会话无效),vaadin,vaadin-flow,vaadin10,Vaadin,Vaadin Flow,Vaadin10,在my Vaadin 14.2.0应用程序中,有一个BeforeLeaveListener,用于在输入脏时显示确认对话框(=输入字段中有未保存的更改)以取消(或有意继续)导航: BeforeLeaveListener listener = new BeforeLeaveListener() { @Override public void beforeLeave(BeforeLeaveEvent event) { if (dirtyFlag.isDirty()) {
BeforeLeaveListener listener = new BeforeLeaveListener() {
@Override
public void beforeLeave(BeforeLeaveEvent event) {
if (dirtyFlag.isDirty()) {
ContinueNavigationAction postponeAction = event.postpone();
// show confirmation dialog and maybe execute a proceed
[...] () -> postponeAction.proceed();
}
}
};
UI.getCurrent().addBeforeLeaveListener(listener);
除了注销之外,这一切都很好。
这是我的注销按钮在开始时的样子(只要我不想推迟/取消注销,它就可以工作):
现在我想推迟注销,直到用户确认应该放弃未保存的更改。(在EventListener中切换这两行似乎是一个好主意,但由于以下原因而不起作用。)
在navigate调用中,BeforeLeaveListener被调用(好),但是注销仍然完成,因为navigate()调用之后的代码被执行(当然,因为它不是阻塞调用),会话无效,用户通过刚刚弹出的确认对话框注销(但用户没有机会确认/拒绝)
我试图将会话失效转移到LoginView(一个BeforeEnterObserver)中,但结果是登录视图被无限循环地重新加载
问:是否有类似“导航到LoginView,如果导航未被推迟或取消,则使会话无效”的内容
解决方法是导航到拦截日志out视图,该视图仅使会话无效并重定向/转发到LoginView:
@Route(value = "logout")
public class LogoutView implements BeforeEnterObserver {
@Override
public void beforeEnter(BeforeEnterEvent event) {
VaadinSession.getCurrent().getSession().invalidate();
event.forwardTo(LoginView.class);
}
}
但在我看来,这只是一个很糟糕的解决方法,有一些开销(创建一个视图只是为了转发到另一个视图).我知道,您没有提到Spring。但事实上,我相信Spring Security在幕后就是这么做的 我的注销按钮(使用Spring Security)如下所示:
new Button("Logout", click -> {
UI.getCurrent().getPage().executeJs("location.assign('logout')");
});
单击后,您将注销并重定向到登录视图()。我想如果你绕道注销视图重定向就可以了
事实上,您甚至可以使用Navigator转到您的LogoutView,这在这里就更好了,因为BeforeLeaveObserver会捕捉到这一点(与通过分配新位置或刷新页面而发出的全新请求相反。有关更多详细信息,请参阅)
我仍然想为您的用例提出另一个想法。我认为这会简单得多,但需要注销链接知道
dirtyFlag
:
Anchor link = new Anchor();
link.getElement().addEventListener("click", e -> {
if(dirtyFlag.isDirty()){
// show Dialog with
// - a confirm btn that calls doLogout() on click
// - a cancel btn that closes the Dialog
} else {
doLogout();
}
});
...
private void doLogout(){
VaadinSession.getCurrent().getSession().invalidate();
UI.getCurrent().navigate(LoginView.class);
}
是的,我使用Spring Security。但我不知道它在“/logout”注册了一个servlet/侦听器。哇,这太神奇了(…或者可能是默认Vaadin项目附带的WebSecurityConfigureAdapter实现中的logout()-call-in方法configure(HttpSecurity))。谢谢大家!<代码>…或者可能是我的WebSecurity配置适配器实现中的logout()-调用方法configure(HttpSecurity)-完全正确。请注意,如果您使用
location.assign('logout')
,BeforeLeaveObserver将不会捕获它,而是使用beforeunload
(请参阅答案中的链接)`
Anchor link = new Anchor();
link.getElement().addEventListener("click", e -> {
if(dirtyFlag.isDirty()){
// show Dialog with
// - a confirm btn that calls doLogout() on click
// - a cancel btn that closes the Dialog
} else {
doLogout();
}
});
...
private void doLogout(){
VaadinSession.getCurrent().getSession().invalidate();
UI.getCurrent().navigate(LoginView.class);
}