Closed davidcr01 closed 1 year ago
The mockup for this page is the following, done in Figma:
The page is generated with the ionic g page pages/login
.
This page is very similar to the Register page #5. The creation and validation of the form are the same as the register page.
About the TypeScript logic of the page, the login.page.ts
file has a login()
function with the following content:
login() {
const credentials = {
username: this.loginForm.get('username').value,
password: this.loginForm.get('password').value,
}
this.http.post<any>('http://localhost/api-token-auth/', credentials).subscribe(
(response) => {
console.log("Logged in correcty!")
// Store the token in the local storage
localStorage.setItem('access_token', response.token);
// this.router.navigateByUrl('');
},
(error) => {
console.error('Log in error', error);
this.errorMessage = 'Provided credentials are not correct'
}
);
}
This function obtains the credentials introduced in the form and makes a POST request to the API using the api-token-auth
URL, which returns a token if the submitted user exists.
If the token exists, it is stored in the storageService
service that allows data to be stored persistently on the user's device encrypted. The module IonicStorage
provides a persistent and secure data storage interface for Ionic applications.
To manage this, a new service has been created. This service is implemented in the storage.service.ts
file.
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';
@Injectable({
providedIn: 'root'
})
export class StorageService {
private _storage: Storage | null = null;
constructor(private storage: Storage) {
this.init();
}
async init() {
const storage = await this.storage.create();
this._storage = storage;
}
async setAccessToken(token: string) {
await this._storage?.set('access_token', token);
}
async getAccessToken(): Promise<string | null> {
return await this._storage?.get('access_token') || null;
}
async removeAccessToken() {
await this._storage?.remove('access_token');
}
}
It provides an initialized secure storage and defines some methods to store the token. This storage is useful to store some information about the player, for example, the ID of the user and the player. Notice that the methods use the IonicStorage API, using set
, get
and remove
methods.
💡 This service can be used by any of the defined pages or components that import the service:
In the import { StorageService } from '../../storage.service';
in the import { IonicStorageModule } from '@ionic/storage-angular';
imports: [
...
IonicStorageModule.forRoot()
],
This module can be integrated with the Ionic Secure Module. It is an enterprise-ready, high-performance data store with SQL or key/value support and offering 256-bit AES encryption. For production purposes, it is a great solution to store the data securely.
For development purposes, and to replace the Ionic Secure Module, a custom solution has been developed to store safely the user data in the device.
A new service of encryption has been created in the project called encryption.service.ts
. This service encrypted with a private key the passed value:
import { Injectable } from '@angular/core';
import { AES, enc } from 'crypto-js';
import env from '../../env.json';
@Injectable({
providedIn: 'root',
})
export class EncryptionService {
private readonly encryptionKey = env.encryptionKey;
encryptData(data: string): string {
const encryptedData = AES.encrypt(data, this.encryptionKey).toString();
return encryptedData;
}
decryptData(encryptedData: string): string {
const decryptedData = AES.decrypt(encryptedData, this.encryptionKey).toString(enc.Utf8);
return decryptedData;
}
}
Notice that:
crypto-js
library is being used. Install it with npm install crypto-js
.env.json
is created and imported. This file contains the privateKey. This is done due to security reasons. Instead of writing the private key in a variable in the code, it is got by a file. To import JSON files, add "resolveJsonModule": true, "allowSyntheticDefaultImports": true,
to the compilerOptions
inside the tsconfig.json
file. This file must be hidden, so its path is added to the .dockerignore
file. Now, the stored token is encrypted in the platform:
this.http.post<any>('http://localhost:8080/api-token-auth/', credentials).subscribe(
async (response) => {
console.log("Logged in correcty!");
console.log(response);
// Store the token in the local storage
const encryptedToken = this.encryptionService.encryptData(response.token);
await this.storageService.setAccessToken(encryptedToken);
A new page Home
has been created. This page only show a loading icon, and it redirects the user depending on his token. If a token is stored, is redirected to the main application (tabs right now). If not, is redirected to the login page.
export class HomePage {
constructor(private router: Router, private storageService: StorageService) { }
ionViewDidEnter() {
setTimeout(async () => {
const token = await this.storageService.getAccessToken();
console.log(token);
if (!token) {
// Redirigir al usuario a la página de inicio de sesión
this.router.navigateByUrl('/login');
} else {
this.router.navigateByUrl('/tabs');
}
}, 2000);
}
}
Notice that the ionViewDidEnter
is used. This method is executed when the page has loaded.
To always load the Home page at the beginning of the app and when a URL does not exist, a new route has been added to the app-routing.module.ts
:
const routes: Routes = [
{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
When opening the app, this page is shown:
When some seconds have passed, the login page is shown:
✔️ If the credentials are not correct, an error is displayed:
✔️ If the credentials are correct, the token is stored and the user is redirected to the application itself:
The tabs
pages are provisional right now, but the redirection works.
If we navigate to the main page (http://localhost), the home page (loading page) is shown and the user is redirected again to the tabs
page as the token has been stored.
Description
The login page will be the index of the applications for non-authenticated users. It will require the
username
andpassword
fields to access to the platform.The login page will have a
Register
button redirecting to the registration page. #5Tasks