3

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

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

但是我对应用程序的目标略有不同:

[用例]

1.用户使用他们的特定凭据登录。

2.Gets Redirected to a 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 所以我想知道是否有人可以帮助我更好地理解这件事?充分赞赏

4

1 回答 1

3

tl;博士

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

让 Vaadin 完成繁重的工作

我怀疑你工作太努力了。

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

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

VaadinSession

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

VaadinSession vaadinSession = VaadinSession.getCurrent() ; 

会话属性(键值存储)

查询该会话对象的键值存储,称为“属性”。键是类型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允许您以文本形式询问类的名称

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

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

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

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

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

要编写的代码大纲

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界面,这里的“上下文”是指整个 Web 应用程序。这是标准的 Java Servlet 东西,完全不是 Vaadin 特有的,但 Vaadin 实际上是一个 Servlet(可能是有史以来最复杂的 Servlet),因此适用此上下文侦听器范例。

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

于 2019-01-20T03:17:53.247 回答