Idea
You only have to log in once and it’s saved on storage. Only if you log out the storage cleaned.
I’m using Capacitor Secure Storage to store the token of the logged-in user to save it so that the user doesn’t have to login every time the RAM is cleaned. It’s not working as I would want it to.
I think it does save the token but doesn’t use it correctly to check if the user is logged or not.
Here’s my code. Only for testing.
service
const helper = new JwtHelperService();
const { SecureStoragePlugin } = Plugins;
const TOKEN_KEY = 'jwt-token';
@Injectable({
providedIn: 'root'
})
export class AuthService {
public user: Observable<any>;
private userData = new BehaviorSubject(null);
constructor(private http: HttpClient, private plt: Platform, private router: Router) {
this.loadStoredToken();
}
loadStoredToken() {
let platformObs = from(this.plt.ready());
this.user = platformObs.pipe(
switchMap(() => {
return from(SecureStoragePlugin.get({key:TOKEN_KEY}));
}),
map(token => {
alert(token.value);
if (token) {
let decoded = helper.decodeToken(token.value);
this.userData.next(decoded);
return true;
} else {
return null;
}
})
);
}
login(credentials: {email: string, pw: string }) {
// Normally make a POST request to your APi with your login credentials
if (credentials.email != 'aa@myemail.com' || credentials.pw != '123') {
return of(null);
}
return this.http.get('https://randomuser.me/api/').pipe(
take(1),
map(res => {
//Random jwt token
return `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Njc2NjU3MDYsImV4cCI6MTU5OTIwMTcwNiwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoiMTIzNDUiLCJmaXJzdF9uYW1lIjoiU2ltb24iLCJsYXN0X25hbWUiOiJHcmltbSIsImVtYWlsIjoic2FpbW9uQGRldmRhY3RpYy5jb20ifQ.4LZTaUxsX2oXpWN6nrSScFXeBNZVEyuPxcOkbbDVZ5U`;
}),
switchMap(token => {
let decoded = helper.decodeToken(token);
this.userData.next(decoded);
let storageObs = SecureStoragePlugin.set({key: TOKEN_KEY, value: token });
return storageObs;
})
);
}
getUser() {
return this.userData.getValue();
}
logout() {
SecureStoragePlugin.remove({ key: TOKEN_KEY}).then(() => {
this.router.navigateByUrl('/');
this.userData.next(null);
});
}
login.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
import { AlertController } from '@ionic/angular';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage implements OnInit {
credentials = {
email: 'aa@myemail.com',
pw: '123'
};
constructor(
private auth: AuthService,
private router: Router,
private alertCtrl: AlertController
) {}
ngOnInit() {}
login() {
this.auth.login(this.credentials).subscribe(async res => {
if (res) {
this.router.navigateByUrl('/members');
} else {
const alert = await this.alertCtrl.create({
header: 'Login Failed',
message: 'Wrong credentials.',
buttons: ['OK']
});
await alert.present();
}
});
}
}
guard
export class AuthGuard implements CanActivate{
constructor(private router: Router, private auth: AuthService, private alertCtrl: AlertController) { }
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
return this.auth.user.pipe(
take(1),
map(user => {
if (!user) {
this.alertCtrl.create({
header: 'Unauthorized',
message: 'You are not allowed to access that page.',
buttons: ['OK']
}).then(alert => alert.present());
this.router.navigateByUrl('/');
return false;
} else {
return true;
}
})
)
}
}
app-routing.module.ts
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';
const routes: Routes = [
{
path: 'members',
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule),
canActivate: [AuthGuard]
},
{
path: '',
loadChildren: () => import('./login/login.module').then( m => m.LoginPageModule)
},
{
path: 'register',
loadChildren: () => import('./register/register.module').then( m => m.RegisterPageModule)
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule {}