davidcr01 / WordlePlus

Repository to store all the documentation, files and structure of my Final Degree Project (TFG in Spanish). The main goal is to develop, as full-stack web developer, a remodel of the Wordle game, including more features and functionalities using Ionic, Django REST Api and PostgreSQL.
1 stars 0 forks source link

Login page (S2) #12

Closed davidcr01 closed 1 year ago

davidcr01 commented 1 year ago

Description

The login page will be the index of the applications for non-authenticated users. It will require the username and password fields to access to the platform.

The login page will have a Register button redirecting to the registration page. #5

Tasks

davidcr01 commented 1 year ago

Update Report

Mockup

The mockup for this page is the following, done in Figma:
image

The page is generated with the ionic g page pages/login.

Development - Login page

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.

Storage

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 .page/component.ts: import { StorageService } from '../../storage.service';

in the .module.ts: 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.

Security

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:

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);
davidcr01 commented 1 year ago

Update Report

Home page

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'
  },
davidcr01 commented 1 year ago

Update Report

Result

When opening the app, this page is shown: image

When some seconds have passed, the login page is shown:

image

✔️ If the credentials are not correct, an error is displayed: image

✔️ If the credentials are correct, the token is stored and the user is redirected to the application itself: image

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.