【问题标题】:User Sessions with Vaadin Flow使用 Vaadin Flow 的用户会话
【发布时间】:2019-06-12 06:53:09
【问题描述】:

我目前是一名初出茅庐的 Java 开发人员,想进入 Vaadin 开发,目前正在尝试为我的应用程序实现用户会话登录。我已经阅读了有关使用 VaadinServlets 的内容:https://vaadin.com/docs/v10/flow/advanced/tutorial-application-lifecycle.html

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

但是我的申请目标略有不同:

[用例]

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

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

3. 2-3 分钟不活动后,用户将被强制退出 SecuredPage 并关闭会话?

@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()");
    }

    }

1 所以我想知道是否有人可以帮助我更好地理解这件事?非常感谢

【问题讨论】:

    标签: vaadin10 vaadin-flow


    【解决方案1】:

    tl;博士

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

    让 Vaadin 完成繁重的工作

    我怀疑你工作太努力了。

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

    不需要redirects。作为 Vaadin 开发人员,您可以完全控制浏览器选项卡/窗口中显示的内容,因此您可以在登录表单和主应用程序内容之间切换。警告:我是 Vaadin Flow 中 @Route 功能的新手,因此可能有一个 niftier way with that feature 在登录和主要内容之间切换。如果您对多个视图使用@Route,则每个视图都应按如下所述测试身份验证。

    VaadinSession

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

    VaadinSession vaadinSession = VaadinSession.getCurrent() ; 
    

    会话属性(键值存储)

    查询该会话对象的key-value 存储,称为“属性”。键的类型为String,值的类型为Object(所有Java 对象的超类)。检索到Object 对象后,您将转换为已知类。您知道该类,因为它是您的代码存储了该属性。

    您的用户登录类

    您将定义一个类来存储您的用户登录相关信息。也许您将其命名为UserLogin

    类似:

    public class UserLogin {
        // Member values.
        String userName ;
        Instant whenAuthenticated ;
    
        // Constructor.
        public UserLogin( String userNameArg , Instant whenAuthenticatedArg ) {
            this.userName = userNameArg ;
            this.whenAuthenticated = whenAuthenticatedArg ;
        }
    }
    

    尝试从会话的键值存储中检索用户登录类的对象

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

    String attributeName = "my-user-login" ;
    UserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;
    

    您可以只使用类名,而不是发明一个属性名。 Class 类允许您将类的ask for the name 作为文本。

    String attributeName = UserLogin.class.getName() ;
    UserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;
    

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

    UserLogin userLogin = vaadinSession.getAttribute( UserLogin.class ) ;
    

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

    如果不为 null,则表示您的用户已经存储了一个活动的 UserLogin 对象。如果您的应用程序的入口点正在执行,他们怎么可能已经登录?如果用户点击浏览器窗口上的 Reload 按钮,就会发生这种情况。 (培训您的用户不要在 single-page web app 上这样做,例如 Vaadin。)

    要编写的代码大纲

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

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

    在某些时候,您可能会在第一个用户连接之前和/或在最后一个用户断开连接之后寻找整个 Web 应用程序生命周期的挂钩,了解 Java Servlet 规范中定义的挂钩。这个钩子是ServletContextListener 接口,其中“上下文”表示您的网络应用程序作为一个整体。这是标准的 Java Servlet 东西,完全不是 Vaadin 特有的,但 Vaadin 实际上是一个 Servlet(可能是有史以来最复杂的 Servlet),因此适用此上下文侦听器范例。

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

    【讨论】:

      猜你喜欢
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      • 2021-08-20
      • 2012-01-03
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      相关资源
      最近更新 更多