I am currently a budding Java developer that wants to get into Vaadin development and currently trying to implement User Session login for my application. I have read about the content regarding the usage of VaadinServlets to do so : https://vaadin.com/docs/v10/flow/advanced/tutorial-application-lifecycle.html.
After relentlessly digging through API documentations and sample codes, I still am not able to understand how to implement the User Sessions for a specific user that logs into my platform. From what I understand is that, I can initialize my user session by using what i have implemented below.
However my aims for the application are slightly different:
[Use Case]
1.User logs in with their specific credentials.
2.Gets Redirected to a SecuredPage (which will create a User Session storing the user's username and retrieves a token?)
3.After 2-3mins of inactivity, the User will get forced out of the SecuredPage and Session closes?
@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 So I was wondering if anybody can help me understand this matter better? Fully Appreciated
The mere existence of a custom-defined user-login object stored as an attribute in the key-value store of your VaadinSession
represents the user having successfully authenticated. No need for all the session-listener code you wrote.
I suspect you are working too hard.
There is no need for your session listeners. Vaadin handles nearly all the Java Servlet details on our behalf.
No need for the redirects. As a Vaadin developer, you are in full control of the content displayed in the browser tab/window, so you can switch between login form and main app content. Caveat: I am new to the @Route
feature in Vaadin Flow, so there may be a niftier way with that feature to flip between login and main-content. And if you are using @Route
for multiple views, each of those views should test for the authentication as described below.
VaadinSession
At the entry point of your Vaadin app code, retrieve the current VaadinSession
object. This VaadinSession
is a wrapper around the javax.servlet.http.HttpSession
class defined by the Java Servlet spec. Vaadin automatically instantiates a session when the user’s browser first connects to your Vaadin web app (actually, Vaadin wraps the session instantiated by your web container). The session is automatically closed when the browser closes its tab/window, a time-out of inactivity occurs, or you programmatically close the session.
VaadinSession vaadinSession = VaadinSession.getCurrent() ;
Interrogate that session object’s key-value store known as “attributes”. The key is of type String
and the value is of type Object
(the superclass of all Java objects). After retrieving the Object
object, you cast to the known class. You know the class, because it is your code that stored the attribute.
You would have defined a class to store your user-login related info. Perhaps you named it UserLogin
.
Something like:
public class UserLogin {
// Member values.
String userName ;
Instant whenAuthenticated ;
// Constructor.
public UserLogin( String userNameArg , Instant whenAuthenticatedArg ) {
this.userName = userNameArg ;
this.whenAuthenticated = whenAuthenticatedArg ;
}
}
Retrieve such an object of that type from the session attributes key-value store.
String attributeName = "my-user-login" ;
UserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;
Rather than invent an attribute name, you could just use the class name. The Class
class lets you ask for the name of a class as text.
String attributeName = UserLogin.class.getName() ;
UserLogin userLogin = vaadinSession.getAttribute( attributeName ) ;
If you want to use the class name as the key in this way, the VaadinSession
class provides a shortcut.
UserLogin userLogin = vaadinSession.getAttribute( UserLogin.class ) ;
Check to see if your UserLogin
object is null. If you retrieved a null
, then you know you have not yet stored an attribute (or willfully stored a null).
If not null, it means your user already has an active UserLogin
object stored. How could they be logged-in already if the entry point of your app is executing? This can happen if the user hits the Reload button on their browser window. (Train your user not to do so on a single-page web app such as 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 …
}
By the way… the discussion above about sessions is scoped to each user’s own connection to your web app in a single web browser tab/window.
At some point you may look for a hook into the lifecycle of your entire web app, before the first user connects and/or after the last user disconnects, learn about the hook defined in the Java Servlet spec. This hook is the ServletContextListener
interface, where “context” means your web app as a whole. This is standard Java Servlet stuff, not at all specific to Vaadin, but Vaadin is actually a Servlet (perhaps the most sophisticated Servlet ever) so this context listener paradigm applies.
You write a class implementing that interface, by writing the before-first-user and the after-last-user methods. Identify your class to the web container by annotating @WebListener
(or alternative means). Search Stack Overflow as this has been covered multiple times already.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With