How can I verify and use the Anonymous User functionality?

Jmix version: 1.1.2
Jmix Studio plugin version: 1.1.4-213
IntelliJ IDEA 2021.3 CE - Build #IC-213.5744.223, built on November 27, 2021
Operating System: macOS 12.0.1 (21A559)
File System: Case-Sensitive Journaled HFS+ (APFS)
Datebase: PostgreSQL 13

Hi Everyone

  1. How can I verify and use the Anonymous User functionality? I have read the documentation Users :: Jmix Documentation and experiemented with this code in the DatabaseUserRepository class with the provided FullAccessRole and also with my CUBA-to-Jmix migrated AnonymousUserRole …

    @Override
    protected void initAnonymousUser(User anonymousUser) {
    Collection authorities = getGrantedAuthoritiesBuilder()
    // .addResourceRole(FullAccessRole.CODE)
    .addResourceRole(AnonymousUserRole.NAME)
    .build();
    anonymousUser.setAuthorities(authorities);
    }

but I do not understand how I can access my application at http://localhost:8080 without provoking the login-screen? I need to present the anonymous user with my other information screens before logging into the application, just like I do in CUBA.

  1. And I still need the ability to choose a new application language before logging in (not while logging in with the login-screen). Gleb Gorelov helped me out with this in CUBA: Cannot set the locale for the initial ExtMainScreen and SideMenu for an Anonymous user before he/she logs in - CUBA.Platform

I am hoping that the solution to number 1 will enable me to refactor my code for number 2. Note, that I also opened a completely new project to experiment with this but the result was the same as with my migrated project.

Any suggestions or ideas? What have I overlooked?

Best regards
Chris

Hi,

In the application.properties file you should enable anonymous access and specify which screen should be displayed for anonymous user:

# enable anonymous access
jmix.ui.allow-anonymous-access=true

# initial screen for anonymous user
jmix.ui.initial-screen-id=MyAnonymousScreen

Allow access to this screen for the AnonymousRole:

@ResourceRole(name = "AnonymousRole", code = AnonymousRole.CODE)
public interface AnonymousRole {

    String CODE = "anonymous-role";

    @ScreenPolicy(screenIds = {"MyAnonymousScreen"})
    void screens();
}

Grant AnonymousRole to the anonymous user in the DatabaseUserRepository:

    @Override
    protected void initAnonymousUser(User anonymousUser) {
        Collection<GrantedAuthority> authorities = getGrantedAuthoritiesBuilder()
                .addResourceRole(AnonymousRole.CODE)
                .build();
        anonymousUser.setAuthorities(authorities);
    }

On the MyAnonymousScreen you may have a button that opens the login screen:

@UiController("MyAnonymousScreen")
@UiDescriptor("my-anonymous-screen.xml")
public class MyAnonymousScreen extends Screen {

    @Autowired
    private Screens screens;

    @Autowired
    private UiProperties uiProperties;

    @Subscribe("showLoginScreenBtn")
    public void onShowLoginScreenClick(Button.ClickEvent event) {
        String loginScreenId = uiProperties.getLoginScreenId();
        Screen loginScreen = screens.create(loginScreenId, OpenMode.ROOT);
        loginScreen.show();
    }
}

The sample project that demonstrates this: jmix-anonymous-screen-sample.zip (94.7 KB)

Hi Maxim

Thank you for the information and your efforts. I was able to activate the anonymous user access with these new appilcation properties and it is working with the AnonymousUserRole that I migrated from CUBA.

But I did find a behavior that is new and maybe a bug…

In CUBA the following code in my MainScreen onInit() controller-handler returned “false” for an anonymous user when visiting the application URL before a login screen is presented:

authenticated = defaultApp.getConnection().isAuthenticated();

but in Jmix the following code returns “true” for an anonymous user:

authenticated = currentAuthentication.getAuthentication().isAuthenticated();

Jmix_anonymous_user_is_authenticated

Is this behavior really correct?

I can check the username in combination with this isAuthenticated() attribute to determine if the authenticated user is the “anonymous” user but I believe that this should not be necessary.

Can you please check this situation and give me further feedback. Thanks in advance.

Best regards
Chris

That’s how Spring security works. The documentation says:

Note that there is no real conceptual difference between a user who is “anonymously authenticated” and an unauthenticated user. Spring Security’s anonymous authentication just gives you a more convenient way to configure your access-control attributes.

If you want to check that your authentication is anonymous you may do the following:

Authentication authentication = currentAuthentication.getAuthentication();
if (authentication instanceof AnonymousAuthenticationToken) {
     log.info("Anonymous authentication");
}

Hi Maxim

Thank you for the additional information/clarification and your example. It works fine.

And in the meantime I found the following code while looking for something else…

boolean authenticated = AppUI.getCurrent().hasAuthenticatedSession();

and authenticated is false for the “anonymous” user, which is the behavior that I was originally searching for. I have not thought about all of the different use cases, so I cannot recommend one solution over the other.

I was also able to refactor my MainScreen to re-implement most of the functionality described in point 2 above. If I have any more problems with that, I will open a new topic.

Best regards
Chris