CodeCoupler UI Authentication
The system can be configured with an authentication module and an authentication application.
The module provides methods to login, logout, provide informations about the current user and its
persistent configuration.
The application provides an UI to enter credentials and call the login
method of the module.
To access the module and use the provided methods you can use the property auth
of a System
instance. To request a login and start the authentication application you can call the method
login
of a System
instance.
Implement an Authentication Application
An authentication application is a regular CodeCoupler Application. The application receives at
startup in addition to the options defined in the system configuration the following options:
module
: Authentication Module
-
The module that should be used to call the login
method.
message
: String
-
An optional message that should be shown to the user.
The only thing the application has to do is to call at any time the method login
of the given
authentication module. If the login fails (an exception will be thrown) the user should be informed
and he should retry the login.
If the login was successful the application must be closed (this.panel.close()
or this.close()
).
Implement an Authentication Module
To write a new stage class you have to extend the CodeCoupler class AuthBase
. The base class
provides methods for event handling:
on(event,handler)
, one(event,handler)
, off([event],[handler])
,
trigger(event,argments)
All other methods must be overriden by your class as follows:
| import { AuthModBase } from "@codecoupler/cc-ui";
export default class extends AuthModBase {
//This is just an example how to implement a cache:
#currentUser;
#currentUserFetched;
//If you want to override the constructor start with "super(options);"
constructor(options) {
super(options);
#currentUser = null;
#currentUserFetched = false;
}
//If called "getUser" try to fetch the current user and to check if the
//login is still valid. The object you return is not specified. You can
//return here whatever you want if the login is valid. If no user login
//exists you have to return "null".
//
//The function should always resolve, never reject. In case of an error it
//have to resolve with null.
async getUser() {
if (!this.#currentUserFetched) {
try {
this.#currentUser = await your_function_to_fetch_current_user();
} catch (e) {
this.#currentUser = null;
}
this.#currentUserFetched = true;
}
return this.#currentUser;
}
//Return an array with permissions. Each permission is represented by a string.
async getPermissions() {
if (!this.#currentUserFetched) await this.getUser();
return this.#currentUser ? extract_permissions_from_user_object(this.#currentUser) : [];
}
//Return an array with permissions. Each permission is represented by a string.
async getRoles() {
if (!this.#currentUserFetched) await this.getUser();
return this.#currentUser ? extract_roles_from_user_object(this.#currentUser) : [];
}
//Implement your logic to login. Use any argument signature you need.
//Do not forget to call "this.trigger("login");"!
async login(username, password) {
try {
await your_function_to_authenticate(username, password);
this.trigger("login");
} catch (e) {
throw convert_error_object_to_string(e);
}
}
//Implement your logic to logout.
//Do not forget to call this.trigger("logout")
logout() {
this.#currentUser = null;
this.trigger("logout");
}
//This is the method to save any configuration key/value-pairs to the user
//object. This should be saved on the remote server. If not possible you
//should always call "await super.saveConfig(key, value)" as fallback.
async saveConfig(key, value) {
await super.saveConfig(key, value);
}
//This is the method to get any configuration key/value-pairs from the user
//object that have been saved with "saveConfig". If not possible you should
//always return the value from "await super.getConfig(key)" as fallback.
async getConfig(key) {
return await super.getConfig(key);
}
}
|
Provided Applications and Modules
CodeCoupler provides the following applications and modules by default:
Authentication Application "Basic"
The application provides an UI to enter just a username and a password. The application is very
flexible and can be adapted to your own needs.
The options that the application expects:
hooks
: Object
-
An object to define hooks to adapt the behavior and appearance. See below for more details.
messages
: Object
-
Define the used texts:
USERNAME
, PASSWORD
, LOGIN
The basic structure is:
| +--------------------------------------+
| +----------------------------------+ |
| | Logo data-role="logo" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Message data-role="message" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Label data-role="username-label" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Input data-role="username" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Label data-role="password-label" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Input data-role="password" | |
| +----------------------------------+ |
| +----------------------------------+ |
| | Button data-role="submit" | |
| +----------------------------------+ |
+--------------------------------------+
|
We go through the following process and call the following hooks:
- Start the panel and build the HTML structure.
- Call the hook
init(panel)
.
- If the hook did not return
false
:
- Resize the panel.
- Set focus to the username field.
- Bind the
Enter
key to trigger the button click.
- After the button was clicked:
- Call the hook
start()
.
- If the hook did not return
false
:
- Disable inputs elements and button. Start Button animation.
- Call the
login(username,password)
method of the module.
- If succeed:
- Call the hook
done()
.
- Close the application.
- If failed:
- The application expects that the thrown error is just a plain string. If not a generic error
message will be generated.
- Call the hook
fail(errorMessage,errorObject)
.
- If the hook did not return
false
:
- Enable inputs elements and button. Stop Button animation.
- Show error message.
- Resize and reposition panel.
Here an example of options which change the logo, hide the labels and translates all other messages:
| {
hooks: {
init: function (panel) {
var $content = $(panel.content);
var $logo = $content.find("[data-role=logo]");
$logo.replaceWith('<img src="logo.png" width="100" height="100">');
$content.find("[data-role=username-label]").hide();
$content.find("[data-role=password-label]").hide();
}
},
messages: {
USERNAME: "Benutzername",
PASSWORD: "Passwort",
LOGIN: "Anmelden"
}
}
|
Authentication Module Mockup
Just for testing purposes. You can login with the username "admin" and the password "admin".
Authentication Module Loopback
Authentication module which works with Loopback as authentication backend in combination with the
package @codecoupler/cc-api-auth
.
Will be instatiated with new AuthModLoopback(options)
. Accepts the following options object:
| {
controller: {
base: "/", //Base path to the API
login: "login", //Controller name for "login"
logout: "logout", //Controller name for "logout"
me: "me" //Controller name for "me"
},
messages: {} //Translate messages (see below)
}
|
In case of an error Loopback sends an status code and a message. This message will be shown in the
authentication application. You can map this messages by status code:
| {
messages: {
500: "Set new message for status 500 here"
}
}
|