Implementing the login/logout process

Let's recap what we have implemented at this point. We have a multi-language LoginFormComponent ready for use (developed in Chapter 3, Implementing Server-Side Components with Internationalization), a UI implementation that shows a PublicComponent or a PrivateComponentdepending on whether a user is authenticated, and an AuthService class that allows us to authenticate a user (if their login credentials are correct) and check whether there is an authenticated user in the session or not.

It's time to complete the login/logout process by implementing the PublicComponent and PrivateComponent classes. Let's start with the PublicComponent class:

public class PublicComponent extends Composite {

    public PublicComponent() {
        LoginFormComponent loginForm = new LoginFormComponent();
        loginForm.setCaptions(
                Messages.get("auth.username"),
                Messages.get("auth.password"),
                Messages.get("auth.login"),
                Messages.get("auth.rememberMe"));

        loginForm.setLoginListener(form -> loginClicked(form));
        setCompositionRoot(loginForm);
    }

    private void loginClicked(LoginFormComponent form) {
        if (!AuthService.authenticate(
                form.getUsername(), form.getPassword())) {
            Notification.show(
                    Messages.get("auth.bad.credentials"),
                            Notification.Type.ERROR_MESSAGE);
        }
    }
}

This component extends Composite and uses the LoginFormComponent as its composition root. The loginClicked method is called when the user clicks the respective button, and it's inside this method where we try to authenticate the user. If the credentials are correct, we show an error notification, but if they are correct, we are not doing anything at all! And actually, we don't really need to do anything else in this class. Do you remember how we implemented the VaadinUI class so that it would show one screen or the other according to the authentication state? Well, all we need to do in order to make this work is add a simple page reload to the AuthService.authenticate method for when the authentication succeeds:

public class AuthService {

    private static final String USERNAME_ATTRIBUTE = "username";

    public static boolean authenticate(
            String username, String password) {

        boolean authentic = "admin".equals(username) &&
                "admin".equals(password);

        if (authentic) {
            VaadinSession.getCurrent().setAttribute(
                    USERNAME_ATTRIBUTE, username);
            Page.getCurrent().reload();
        }

        return authentic;
    }
    ...
}

That's right! Since the VaadinUI.init method is called when the user refreshes the browser and our implementation checks whether there's an authenticated user in the HTTP session (via the AuthService class), we don't need to do anything else.

How about the other way around? When the user logs out, we should perform two actions:

  1. Remove all the data in the HTTP session (invalidate the session).
  2. Refresh the browser (in order to invoke the VaadinUI.init method and automatically show the PublicComponent).

It's just reasonable to implement this functionality in the AuthService class:

public class AuthService {
    ...

    public static void logout() {
        VaadinService.getCurrentRequest().getWrappedSession()
                .invalidate();
        Page.getCurrent().setLocation("");
    }
}

The invalidate method removes any values from the HTTP session and invalidates it. The server will create a new session if the application is requested again.

Servers maintain sessions in several ways, such as through cookies or URL rewriting. Depending on your specific server, you might have to call VaadinService.reinitializeSession(VaadinService.getCurrentRequest()) to ensure a new session key is generated after you invalidate a session.

Notice how we reloaded the browser this time. Instead of calling the Page.reload() method, we are making sure that the URL in the browser requests the starting URL for the web application. This will also remove, for example, any fragments or parameters from the URL that may contain sensitive information.

Sensitive information refers to any kind of data, information, or knowledge that must be protected against unauthorized access.

Finally, the PrivateComponent class should be pretty straightforward to implement. For the sake of completeness, here's the code:

public class PrivateComponent extends Composite {

    public PrivateComponent() {
        Label label = new Label(
                "User: " + AuthService.getAuthenticatedUser());
        Button logOutButton = new Button(
                Messages.get("auth.logout"),e -> logoutClicked());
        setCompositionRoot(new VerticalLayout(label,
                logOutButton));
    }

    private void logoutClicked() {
        AuthService.logout();
    }
}

Notice the AuthService.getAuthenticatedUser() method. You can implement that method with one line of code:

public class AuthService { 
    ... 
 
    public static String getAuthenticatedUser() { 
        return (String) VaadinSession.getCurrent().getAttribute( 
                USERNAME_ATTRIBUTE); 
    } 
} 
Remember to use HTTPS (HTTP Secure) any time you have a web application with a login form that sends user credentials through the network. By enabling HTTPS, the data is encrypted, preventing man-in-the-middle attacks. You can learn more about how to enable HTTPS at https://vaadin.com/blog/enabling-https-in-your-java-server-using-a-free-certificate.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset