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()
andgetTimeZone()
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()
andgetTimeZone()
methods described above will throw theIllegalStateException
.
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:
BruteForce Protection
The framework has a mechanism for the protection against password brute force cracking.
The jmix.security.bruteforceprotection.enabled application property enables the protection. If the protection is enabled, the combination of user login and IP address is blocked for a time interval in case of multiple unsuccessful login attempts. A maximum number of login attempts for the combination of user login and IP address is defined by the jmix.security.bruteforceprotection.maxLoginAttemptsNumber application property. Blocking interval in seconds is determined by the jmix.security.bruteforceprotection.blockInterval application property.
-
jmix.security.bruteforceprotection.enabled
Enables a mechanism for the protection against password brute force cracking. The default value:
false
.
-
jmix.security.bruteforceprotection.blockInterval
Defines the blocking interval in seconds after exceeding a maximum number of failed login attempts if the jmix.security.bruteforceprotection.enabled property is on. The default value:
60 seconds
.
-
jmix.security.bruteforceprotection.maxLoginAttemptsNumber
Defines a maximum number of failed login attempts for the combination of user login and IP address if the jmix.security.bruteforceprotection.enabled property is on. The default value:
5
.
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";
}