Coding authorization logic in UI components

The first approach we will discuss is including the authorization logic in the UI components themselves. This is what we have done in the example application, where we show a PrivateComponent if the user is authenticated or a PublicComponent if they are not. You can extrapolate this and use it with, for example, roles. Suppose there were two roles: employee and admin. You have to show a hypothetical AdminComponent to users with the role admin and an EmployeeComponent to users with the employee role. You can easily code a method that returns the right component according to the role as follows:

private Optional<Component> getComponent(User user) {

    if (user.getRole().equals(Role.Admin)) {
        return new AdminComponent();

    } else if (user.getRole().equals(Role.Employee)) {
        return new EmployeeComponent();
    }

    return Optional.empty();
}

If a new Role appears in future, you can simply add another if clause to cover the case.

What if there's no need for a completely new UI component for a role? For example, let's say the EmployeeComponent must show a delete button only for users with the employee role, and so not for users with the trainee role. The easier solution is to code this logic inside the EmployeeComponent class itself, using something like the following:

public class EmployeeComponent extends Composite {
    public EmployeeComponent() {
        ...

        User user = AuthService.getCurrentUser();

        if (user.getRole().equals(Role.Employee)) {
            Button delete = new Button();
            someLayout.addComponent(delete);
        }
        ...
    }
}

A good thing about this approach is that you can follow the code to understand what's visible and what's not. However, you might end up with authorization code all over the source code. Well, at least over the UI-related classes. This is, however, a valid approach and you should at least consider it.

A disadvantage of this way of implementing authorization is that it couples UI code with authorization code. This makes it a bit more difficult for software reuse. The preceding class, for example, cannot be used in a different application without carrying the AuthService class. Fortunately, we can easily decouple this class from the authentication stuff. The key is the principle of least privilege.

The principle of least privilege states that a software entity should have access to the least or minimum amount of data it requires to perform its function. Can you see how the EmployeeComponent class violates this principle? All the class needs to know is whether to show the delete button or not. It doesn't really care about roles and authentication logic. We are passing way too much information to it. What's the minimal amount of information this class needs to fulfill its requirements? A simple Boolean telling it whether to show the delete button or not. That's it. A possible implementation can include a parameter in the constructor for this purpose. Here's an example:

public class EmployeeComponent extends Composite { 
    public EmployeeComponent(boolean showDeleteButton) { 
        ... 
 
        if (showDeleteButton) { 
            Button delete = new Button(); 
            someLayout.addComponent(delete); 
            ... 
        } 
        ... 
    } 
} 

We just removed the coupling between this class and the authentication logic. However, we moved the authentication logic somewhere else. Now the client of the EmployeeComponent class must configure it depending on the authorization rules. It's not such a bad thing considering that such a client is already coupled to the AuthService class, right? Take a look at the new implementation:

private Optional<Component> getComponent(User user) { 
 
    if (user.getRole().equals(Role.Admin)) { 
        return new AdminComponent(); 
 
    } else if (user.getRole().equals(Role.Employee)) { 
        return new EmployeeComponent(true); 
 
    } else if (user.getRole().equals(Role.Trainee)) { 
        return new EmployeeComponent(false); 
    } 
 
    return Optional.empty(); 
} 
The Optional class serves as a container for a value that may or may not be null (we are not talking about a Vaadin Container here; the Container interface was removed in Vaadin Framework 8.0). Optional helps to decrease the number of null checks in your code. Instead of returning a null value from a method, you can return an Optionalwhich is empty when the enclosing value is null. This way, the client of the method knows that the returned value might be null. Bear in mind that the original purpose of the Optional class is to serve as an optional return value. Avoid using Optional in method parameters.

The main takeaway of this discussion is to keep in mind that you can provide configuration options for your UI components. Don't just unnecessarily couple them with authentication classes. Provide parameters in the constructors, setters, or even configuration classes if the complexity requires it in order to tell the UI component how it should look and behave.

..................Content has been hidden....................

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