If you want do some custom checks when a user logs in, it is possible to override the Mendix login mechanism.
With this, you can do a lot of useful things. For example:
- Implement a custom user blocking mechanism, e.g. block all users that are linked to a certain company.
- Only allow users to log in from certain IP addresses
- Dynamically assign user roles when logging in
- Etc. etc. (leave your comment below for more ideas!)
To override the standard login, we need to do some Java coding. Create a new Java action ReplaceLoginAction, with no parameters. Call this Java action on startup of the application, by adding a startup microflow, and adding a call to this Java action there. Add the following Java code to the Java action:
// BEGIN USER CODE LoginActionListener loginActionListener = new LoginActionListener(); loginActionListener.addReplaceEvent(CustomLoginAction.class.getName()); Core.addUserAction(CustomLoginAction.class); Core.addListener(loginActionListener); return true; // END USER CODE
You need to added 2 Java class files to your module’s Javasource folder:
LoginActionListener.java:
import com.mendix.core.Core; import com.mendix.core.action.user.LoginAction; import com.mendix.systemwideinterfaces.core.UserActionListener; public class LoginActionListener extends UserActionListener<LoginAction> { public LoginActionListener() { super(LoginAction.class); } @Override public boolean check(LoginAction action) { Core.addUserAction(CustomLoginAction.class); return true; } }
And CustomLoginAction.java:
public class CustomLoginAction extends UserAction<ISession> { private String userName; private String password; private IMxRuntimeRequest request; private String currentSessionId; public final static String USER_NAME_PARAM = "userName"; public final static String PASSWORD_PARAM = "password"; public CustomLoginAction(Map<String, ? extends Object> params) { super(Core.createSystemContext()); this.userName = (String) params.get(USER_NAME_PARAM); this.password = (String) params.get(PASSWORD_PARAM); this.currentSessionId = (String)params.get("currentSessionId"); this.request = (IMxRuntimeRequest)params.get("request"); } @Override public ISession executeAction() throws Exception { IUser user = Core.getUser(getContext(), this.userName); if (user == null) throw new AuthenticationRuntimeException("Login FAILED: unknown user '" + this.userName + "'."); else if (user.isWebserviceUser()) throw new AuthenticationRuntimeException("Login FAILED: client login attempt for web service user '" + this.userName + "'."); else if (user.isAnonymous()) throw new AuthenticationRuntimeException("Login FAILED: client login attempt for guest user '" + this.userName + "'."); else if (user.isActive() == false) throw new AuthenticationRuntimeException("Login FAILED: user '" + this.userName + "' is not active."); else if (user.isBlocked() == true) throw new AuthenticationRuntimeException("Login FAILED: user '" + this.userName + "' is blocked."); else if (user.getUserRoleNames().isEmpty()) throw new AuthenticationRuntimeException("Login FAILED: user '" + this.userName + "' does not have any user roles."); // You can even call Microflows here!, like this: Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("User", user.getMendixObject()); //this will call the microflow LoginAllowed that should have a User parameter and returns true if the user is allowed to log in boolean allowed = Core.execute(getContext(), "MyModule.LoginAllowed", parameters); if (!allowed) throw new AuthenticationRuntimeException("Login FAILED: user "+this.userName); if (!Core.authenticate(Core.createSystemContext(), user, this.password)) //password check throw new AuthenticationRuntimeException("Login FAILED: invalid password for user '" + user.getName() + "'."); ISession session = Core.initializeSession(user, this.currentSessionId); return session; } }
This executeAction() method will be called when a login-attempt is made, and will do the standard checks that Mendix does when logging in, plus call a microflow LoginAllowed in which you can do your own custom stuff. This can, for example, check whether the application is open for non-admin users, like this:
This microflow will be called by the CustomLoginAction in system context, which allows you to do almost anything! Just be careful for security and performance issues if you do too much here 🙂
Leave a Reply