Docs

Controlling Service Access

How to specify the role-based access control rules as annotations for the browser-callable service class or its individual methods.

When developing server-side views, access control is implemented using regular Java approaches: servlet-container-based security, third-party libraries, or session-based solutions.

This article describes all the pieces needed for securing client-centric applications.

Securing Browser-Callable Services

The first step is to configure authorization of each service that the application exposes.

Consider the simple browser-callable service defined in the following class:

Source code
CounterService.java
@BrowserCallable
@PermitAll
public class CounterService {
    public int addOne(int number) {
        return number + 1;
    }
}

Hilla access-control features are enabled by default for any service method. If not specified in Java code explicitly, a Principal object must be present in the request before invoking a service method. The HttpServletRequest.getUserPrincipal() Java API is used for the check.

At this point, the servlet container or the application needs to be configured appropriately to handle user authentication. This is described in Authentication with Spring Security.

Security Options

By default, all anonymous and authenticated requests are denied. To change the default behavior, place a security Java annotation on either the service class or the service method. The following annotations are available:

  • @PermitAll Allows any authenticated user to call a method via the request.

  • @RolesAllowed Grants access to users having the roles specified in the annotation value. Roles are covered in the next section.

  • @DenyAll Disallows anyone from calling the method via the request. The default.

  • @AnonymousAllowed Permits anyone to call the method via the request without authorization.

A security annotation that’s placed on a class is applied to any public method of this class that has no security annotations. If the method has security annotations, any class-level annotation is discarded and only method-level ones are applied.

If there are multiple annotations specified on some entity, the following rules are applied:

  • DenyAll overrides other annotations

  • AnonymousAllowed overrides RolesAllowed and PermitAll

  • RolesAllowed overrides PermitAll

Example:

Source code
MyService.java
@BrowserCallable
@PermitAll
public class MyService {

  @DenyAll
  public void deniedMethod() {
    // Not possible to call by any request. Since there
    // is a `@PermitAll` annotation on the
    // class, we specify this one on a method to override
    // the class one.
  }

  @AnonymousAllowed
  public void anonymousMethod() {
    // Possible to call by any request (even without
    // authorization) since method level annotation
    // overrides class-level one
  }

  public void permittedToAllMethod() {
    // Permitted to all authenticated users as per the
    // class annotation.
  }

  @RolesAllowed("ROLE_ADMIN")
  public void permittedToRoleMethod() {
    // Permitted to all authenticated users having the
    // role ROLE_ADMIN.
  }
}

Defining User Permissions

As mentioned in the previous section, every user can have roles and this may affect their ability to access some service methods. This section explains how to specify these for each user.

Browser-callable services check the existence of roles by using the HttpServletRequest.isUserInRole(String) Java API.

After the servlet container has been configured to handle user authentication, when the server receives a request for the secured service, the user and its roles are checked. If everything is OK, the method is executed.

Accessing User Information in a Service Method

When access to the UserPrincipal is required in a service, call the VaadinRequest.getCurrent() method to access the HttpServletRequest API.

Source code
EchoService.java
@BrowserCallable
public class EchoService {
    public String saySomething(String message) {
        return VaadinRequest.getCurrent().getUserPrincipal().getName() + " says: " + message;
    }
}
Source code
frontend/index.ts
import { EchoService } from 'Frontend/generated/EchoService';

EchoService
    .saySomething("It's snowing in Turku")
    .then(response => console.log(response));

Client Side Authentication

If it’s required to know, on the client side, whether a user is authenticated, please read Checking Authentication.

CSRF Protection of Browser-Callable Services

Browser-callable services are protected from Cross-Site Request Forgery (CSRF) attacks using the same approach as Vaadin. See Cross-Site Request Forgery in the Vaadin Flow security guide for more details.

Updated