Users

User Entity

Users of a Jmix application are defined by the User class that is automatically generated by Studio in a new project. It is a JPA entity implementing the JmixUserDetails interface which has a number of methods required by the framework:

  • getUsername() returns a unique user name.

  • getPassword() returns a hashed password.

  • isEnabled(), isAccountNonExpired(), isAccountNonLocked(), isCredentialsNonExpired() indicate whether the user can log in to the system.

  • getAuthorities(), setAuthorities() are used by the framework to associate the user with a set of permissions upon login.

Users are stored in the main database of your application. By default, the User entity and the corresponding database table have the following attributes:

  • id, version are the standard primary key and optimistic locking attributes.

  • username, password, enabled store values returned by the methods of the JmixUserDetails interface.

  • email, firstName, lastName store additional information about users.

You can define any number of additional attributes required for your application, for example, department or position.

User Management

A new project contains the 010-init-user.xml database migration script that creates a user with the admin/admin username/password and grants the user full access to the application by associating the entity with the system-full-access role.

A new project also contains the UI screens for managing users, see ApplicationUsers. These screens allow you to create, edit and remove users, change and reset their passwords. To assign roles to a user, click the Role assignments button in the user browser.

The framework provides the ui-minimal role that gives permissions to log in to UI and use some common UI elements. Assign this role to new users that will interact with the application through the UI, otherwise they won’t be able to log in.

Built-in Users

Any Jmix application with the standard security subsystem has two built-in user objects:

  • Anonymous user object corresponds to not authenticated users. It allows you to grant some permissions to users before they log in.

  • System user object is required for the system authentication mechanism. It is used when there is no real user interacting with the application, for example, when the application is starting up, or when a business method is called by a scheduler.

The built-in user objects are not stored in the database but created on the application startup by the DatabaseUserRepository class of your project. You can customize both users in the initAnonymousUser() and initSystemUser() methods of this class. By default, the system user is associated with the system-full-access role and hence has all permissions. The anonymous user has no permissions by default.

User Substitution

The system administrator can give a user an ability to substitute another user. The substitution means the user has the security permissions and restrictions of the substituted user. For example, if Alice substitutes Bob, she logs in to the application as Alice but has the Bob’s roles.

To see the feature in action, do the following:

  1. Log in as admin and create at least one more user with the UI: minimal access role.

  2. Select admin in the Users table and click Additional → User substitution. You will see a list of users that admin can substitute.

  3. Add your new user to the list of users substituted by admin.

  4. Now you will see that the current user name in the userIndicator component of the main screen has changed to a drop-down list that contains the substituted user. If you select this user, the workspace will change as if you re-login as this user. But all audit features will still register admin - the logged-in user.

The CurrentUserSubstitution bean can be used to obtain a currently substituted user, an authenticated user, or the effective user (which is substituted user in case of substitution, authenticated one otherwise).

For example:

@Autowired
private CurrentUserSubstitution currentUserSubstitution;

private String getSubstitutedUserName() {
    User substitutedUser = (User) currentUserSubstitution.getSubstitutedUser();
    return substitutedUser == null ? "" : substitutedUser.getUsername();
}
  • The CurrentAuthentication.getUser() method always returns the authenticated user.

  • The CurrentAuthentication.getAuthentication().getAuthorities() returns authorities of the effective user. That is, in the case of substitution, these authorities differ from the authorities of the authenticated user.