Vaadin Flow 的用户会话

Che*_*Lun 4 vaadin10 vaadin-flow

我目前是一名崭露头角的 Java 开发人员,想要进入 Vaadin 开发,目前正在尝试为我的应用程序实现用户会话登录。我已阅读有关使用 VaadinServlet 执行此操作的内容: https: //vaadin.com/docs/v10/flow/advanced/tutorial-application-lifecycle.html

在不断地挖掘 API 文档和示例代码之后,我仍然无法理解如何为登录到我的平台的特定用户实现用户会话。据我了解,我可以使用下面实现的内容来初始化我的用户会话。

然而,我的应用程序目标略有不同:

[使用案例]

1.用户使用其特定凭据登录。

2.重定向到安全页面(这将创建一个存储用户用户名的用户会话并检索令牌?)

3.2-3 分钟不活动后,用户将被迫退出安全页面并且会话关闭?

@WebServlet(urlPatterns = "/*", name = "VaadinFlowServlet", asyncSupported = true)
@VaadinServletConfiguration(heartbeatInterval = 5, productionMode = false)
public class LoginServlet extends VaadinServlet implements SessionInitListener, SessionDestroyListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginServlet.class);

    // <Method> ::servletInitialized():: -> handles most of the servlet customization. (write my servlet customization under this function.
    //          ::getService()::         -> returns a VaadinServletService type?
    //          ::addSessionInitListener(this)::    -> An event listener that can be registered to a VaadinService to get an event -> when a new Vaadin service session is initialized for that service.
    //          ::addSessionDestroyListener(this):: -> A listener that gets notified when a Vaadin service session is no longer used.
    @Override
    protected void servletInitialized() throws ServletException {
        super.servletInitialized();
        getService().addSessionInitListener(this);
        getService().addSessionDestroyListener(this);

    }

    // <Method>     ::sessionInit::      -> Starts Session?
    // <Parameter>  ::SessionInitEvent:: -> Event gets fired when a new Vaadin service session is initialized for a Vaadin service.
    @Override
    public void sessionInit(SessionInitEvent event) throws ServiceException{
        // Do Session start stuff here
        // Creates a Session?

        LOGGER.info("session init() "
                + " Session-ID: " + event.getSession().getSession().getId()
                + " CSRF: " + event.getSession().getCsrfToken());

    }

    // <Method>     ::sessionDestroy:: -> Stops Session?
    // <Parameter>  ::SessionDestroyEvent:: -> Event fired when a Vaadin service session is no longer in use.
    @Override
    public void sessionDestroy(SessionDestroyEvent event) {
        // Do session end stuff here
        LOGGER.info("session destory()");
    }

    }

Run Code Online (Sandbox Code Playgroud)

1 所以我想知道是否有人可以帮助我更好地理解这件事?充分赞赏

Bas*_*que 6

太长了;博士

\n\n

仅存在作为属性存储在您的键值存储中的自定义用户登录对象VaadinSession就表示用户已成功通过身份验证。不需要您编写的所有会话侦听器代码。

\n\n

让 Vaadin 承担繁重的工作

\n\n

我怀疑你工作太辛苦了。

\n\n

不需要您的会话侦听器。Vaadin 代表我们处理几乎所有 Java Servlet 详细信息。

\n\n

不需要重定向。作为 Vaadin 开发人员,您可以完全控制浏览器选项卡/窗口中显示的内容,因此您可以在登录表单和主应用程序内容之间切换。警告:我对 Vaadin Flow 中的功能很陌生,因此该功能@Route可能有一种更好的方法来在登录和主要内容之间切换。如果您使用多个视图,则每个视图都应测试身份验证,如下所述。@Route

\n\n

VaadinSession

\n\n

在 Vaadin 应用程序代码的入口点,检索当前VaadinSession对象。这是Java Servlet规范定义的类的VaadinSession包装器。当用户\xe2\x80\x99s 浏览器首次连接到您的 Vaadin Web 应用程序时,Vaadin 会自动实例化会话(实际上,Vaadin 会包装由您的Web 容器实例化的会话)。当浏览器关闭其选项卡/窗口、发生不活动超时或您以编程方式关闭会话时,会话将自动关闭。javax.servlet.http.HttpSession

\n\n
VaadinSession vaadinSession = VaadinSession.getCurrent() ; \n
Run Code Online (Sandbox Code Playgroud)\n\n

会话属性(键值存储)

\n\n

询问名为 \xe2\x80\x9cattributes\xe2\x80\x9d 的会话对象\xe2\x80\x99s键值存储。键是类型String,值是类型Object(所有 Java 对象的超类)。检索Object对象后,您将转换为已知的类。您知道该类,因为它是存储该属性的代码。

\n\n

您的用户登录类

\n\n

您将定义一个类来存储用户登录相关信息。也许你给它起了名字UserLogin

\n\n

就像是:

\n\n
public class UserLogin {\n    // Member values.\n    String userName ;\n    Instant whenAuthenticated ;\n\n    // Constructor.\n    public UserLogin( String userNameArg , Instant whenAuthenticatedArg ) {\n        this.userName = userNameArg ;\n        this.whenAuthenticated = whenAuthenticatedArg ;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

尝试从 session\xe2\x80\x99s 键值存储中检索用户登录类的对象

\n\n

从会话属性键值存储中检索该类型的此类对象。

\n\n
String attributeName = "my-user-login" ;\nUserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以只使用类名称,而不是发明属性名称。该类Class允许您以文本形式询问类的名称。

\n\n
String attributeName = UserLogin.class.getName() ;\nUserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果你想以这种方式使用类名作为键,类VaadinSession提供了一个快捷方式。

\n\n
UserLogin userLogin = vaadinSession.getAttribute( UserLogin.class ) ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

检查您的UserLogin对象是否为空。如果您检索到 a null,那么您就知道您尚未存储属性(或故意存储 null)。

\n\n

如果不为空,则意味着您的用户已经UserLogin存储了一个活动对象。如果您的应用程序的入口点正在执行,他们怎么可能已经登录?如果用户点击浏览器窗口上的“重新加载”按钮,就会发生这种情况。(训练您的用户不要在Vaadin 等单页 Web 应用程序上这样做。)

\n\n

编写代码的概要

\n\n
UserLogin userLogin = vaadinSession.getAttribute( UserLogin.class ) ;\nif( Objects.isNull( userLogin ) ) {\n    \xe2\x80\xa6 display login form \xe2\x80\xa6\n    \xe2\x80\xa6 when authenticated, instantiate a `UserLogin` and store as attribute \xe2\x80\xa6\n    if( authenticationSuccessful ) {  // Testing some did-user-authenticate variable you defined in your login-form.\n        Instant whenAuthenticated = Instant.now() ;  // Capture the current moment in UTC. \n        UserLogin userLogin = new UserLogin( userName , whenAuthenticated ) ;\n        VaadinSession.getCurrent().setAttribute( UserLogin.class , userLogin ) ;  // Using class name as the `String` key tracking this `userLogin` object.\n        \xe2\x80\xa6 switch content of the tab/window from authentication form to your main app content \xe2\x80\xa6\n    } \n} else {  // Else not null. User already authenticated. User may have hit "Reload" button in browser. \n    \xe2\x80\xa6 display app content \xe2\x80\xa6 \n    \xe2\x80\xa6 perhaps log this event \xe2\x80\xa6 maybe user needs to be trained to not hit Reload on a Single-Page Web App \xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

顺便说一句,\xe2\x80\xa6 上面关于会话的讨论仅限于每个用户\xe2\x80\x99 在单个 Web 浏览器选项卡/窗口中与您的 Web 应用程序的连接。

\n\n

在某些时候,您可能会在整个 Web 应用程序的生命周期中寻找一个钩子,在第一个用户连接之前和/或最后一个用户断开连接之后,了解 Java Servlet 规范中定义的钩子。这个钩子是ServletContextListener接口,其中 \xe2\x80\x9ccontext\xe2\x80\x9d 表示整个 Web 应用程序。这是标准的 Java Servlet 内容,一点也不特定于 Vaadin,但 Vaadin 实际上是一个 Servlet(可能是有史以来最复杂的 Servlet),因此适用此上下文侦听器范例。

\n\n

您可以通过编写 before-first-user 和 after-last-user 方法来编写一个实现该接口的类。通过注释(或其他方式)向 Web 容器标识您的类@WebListener。搜索 Stack Overflow,因为这已经被多次报道过。

\n