Authentication

Authentication is the process of verifying the identity of a user or process that interacts with the system. For example, the system can authenticate users by their username and password. For authenticated users, the system can perform authorization, which is a check of permissions to a particular resource.

Jmix directly uses Spring Security servlet authentication, so if you are familiar with this framework, you can easily extend or override the standard authentication mechanism provided by Jmix out-of-the-box.

Current User

To determine who is currently authenticated, use the CurrentAuthentication bean. It has the following methods:

  • getUser() returns the currently authenticated user as UserDetails. You can cast it to the class of users defined in your project.

  • getAuthentication() returns the Authentication object set in the current execution thread. You can use it to get the collection of current user authorities. In the standard Jmix security implementation, the collection contains authority objects for each resource and row-level role assigned to the user.

  • getLocale() and getTimeZone() return the locale and time zone of the current user.

  • isSet() returns true if the current execution thread is authenticated, that is contains information about the user. If it’s not, getUser(), getLocale() and getTimeZone() methods described above will throw the IllegalStateException.

Below is an example of getting the information about the current user:

@Autowired
private CurrentAuthentication currentAuthentication;

private void printAuthenticationInfo() {
    UserDetails user = currentAuthentication.getUser();
    Authentication authentication = currentAuthentication.getAuthentication();
    Locale locale = currentAuthentication.getLocale();
    TimeZone timeZone = currentAuthentication.getTimeZone();

    System.out.println(
            "User: " + user.getUsername() + "\n" +
            "Authentication: " + authentication + "\n" +
            "Roles: " + getRoleNames(authentication) + "\n" +
            "Locale: " + locale.getDisplayName() + "\n" +
            "TimeZone: " + timeZone.getDisplayName()
    );
}

private String getRoleNames(Authentication authentication) {
    return authentication.getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .collect(Collectors.joining(","));
}
CurrentAuthentication is just a wrapper around SecurityContextHolder, so it is fully compatible with all Spring Security mechanisms.

Client Authentication

The backend of a Jmix application can have different clients, for example, Backoffice UI, GraphQL, or REST API. Each client has its own standard authentication mechanism explained in the respective sections of the documentation:

System Authentication

The execution thread can be not authenticated if it was started by an internal scheduler or handles a request from the JMX interface. At the same time, your business logic or data access code usually requires information on who is currently working with the system for logging or authorization.

To temporarily associate the current execution thread with a user, use the SystemAuthenticator bean. It has the following methods:

  • withSystem() - accepts a lambda and executes it as the system user.

  • withUser() - accepts a username of a regular application user and a lambda and executes the lambda as the given user with their permissions.

Below is an example of authenticating an MBean operation:

@Autowired
private SystemAuthenticator systemAuthenticator;
@Autowired
private CurrentAuthentication currentAuthentication;

@ManagedOperation
public String doSomething() {
    return systemAuthenticator.withSystem(() -> {
        UserDetails user = currentAuthentication.getUser();
        System.out.println("User: " + user.getUsername()); // system
        // ...
        return "Done";
    });
}

@ManagedOperation
public String doSomething2() {
    return systemAuthenticator.withUser("admin", () -> {
        UserDetails user = currentAuthentication.getUser();
        System.out.println("User: " + user.getUsername()); // admin
        // ...
        return "Done";
    });
}

You can also use the @Authenticated annotation to authenticate an entire bean method as executed by the system user. For example:

@Autowired
private CurrentAuthentication currentAuthentication;

@Authenticated // authenticates the entire method
@ManagedOperation
public String doSomething3() {
    UserDetails user = currentAuthentication.getUser();
    System.out.println("User: " + user.getUsername()); // system
    // ...
    return "Done";
}