send data when routing angular 6 - angular6

i want to show a message in my authentification page when my token expires.
the app has a guard that checks in every request if user is still authenticated or not(token is still valid or not).
my problem is when i used localstorage and session storageto store the variable "expired". expired has always true since it's stored in the navigator. Any other solutions?
I am new to angular so please any help ?
what i want to show in my login page if expired is true:
<span *ngIf="expired" class="help-block text-danger">
Votre session a expiré !
</span>
and here is the guard code :
#Injectable()
export class AuthGuard implements CanActivateChild {
constructor(private router: Router, private localSt:
LocalStorageService, private loginService: LoginService) {
}
canActivateChild(childRoute: ActivatedRouteSnapshot, state:
RouterStateSnapshot) {
if (this.loginService.isAuthenticated()) {
sessionStorage.setItem("expired", 'false');
return true;
}
sessionStorage.setItem("expired", 'true');
this.router.navigate(['/login']);
return false;
}
}

what I do to show "The session has expired" is:
If the user is idle, or navigating to a URL without the proper permissions I send him/her to the login page through a function on a shared service
endSesion( message ) {
window.localStorage.clear(); //to clear all session variables, tokens and stuff
window.localStorage.setItem('message',message) // save as the only left thing in LS
this.router.navigate(['login']);
}
And in the constructor or the ngOnInit of the login component
ngOnInit() {
this.message = window.localStorage.getItem('message'); // get the message from LS
if ( this.message ) {
alert('Dude!: ' + this.message ); //maybe sweetalert will be nicer to look at
}
}
This way you dont only use to throw user out beacuse a session expired but maybe if not permission or maybe if you check another security issue even froma backend response.

Related

Angular show Success Message of Submit in other Route

I do a http post with a header. After this Post I navigate to a List of Customers and want to show SuccesMessage that Entry is included. How can I display message on other route?
Here is my Code:
postData({
let url = "api.url"
var header = new HttpHeaders .... // etc.
this.http.post(url, { company: this.form.value.company }, { headers (header)}).toPromise().then((data: any) => { console.group(data) })
After post route to page an show message:
this.router.navigate(['customer']);
this.showMsg = true;
Here is my html
<div *ngIf="showMsg">Success</div>
But no success message is shown. Why? And what do I have to do? Thank you so much for help!
You need to use a data sharing entity such as a service. For example you could have a service containing this:
private msgSubject: BehaviorSubject<void> = new BehaviorSubject<void>(void 0);
public msg$: Observable<void> = this.msgSubject.asObservable();
showMsg(): void {
this.msgSubject.next();
}
then in the component you navigate to after redirection you just have to inject the service and then subscribe to the observable msg$:
this.msgService.msg$.subscribe(() => (this.showMsg = true));
You will also need to call the showMsg method of the service once your post is successful.

Session Storage does not clear out on logout and does not immediately display result on login Angular 8

The user logs into the application where it checks for the loginID. If validated, the user details are returned through the authentication service. Now I am setting firstName, lastName, and id in sessionStorage to display the name on the sidebar immediately as user logs in. But firstName and lastName are only displayed either on home page refresh else it displays nothing or the previous user's name. On logout, I am removing the items from the sessionStorage.
Login Routing code
this.authenticationService.login(this.username)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
Routing Code:
{ path: '', component: HomepageComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent, },
{ path: 'homepage', component: HomepageComponent, canActivate: [AuthGuard]},
AuthGuard Code:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const currentUser = this.authenticationService.currentUserValue;
if (currentUser) {
return true;
}
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
Code:
function authenticate() {
const { username } = body;
const user = users.find(x => x.username === username);
if (!user) return error('wrong username');
return ok({
id: user.id,
username: user.username,
firstName: user.firstName,
lastName: user.lastName,
token: 'fake-jwt-token'
})
Authentication Service on login and logout. At login, the username is passed to the login method and then sent for validation to authenticate method. The response is then returned.
login(username: string) {
return this.http.post<any>(`${environment.api}/users/authenticate`, { username })
.pipe(map(user => {
sessionStorage.setItem('firstName', JSON.stringify(user.firstName));
sessionStorage.setItem('lastName', JSON.stringify(user.lastName));
sessionStorage.setItem('id', JSON.stringify(user.id));
this.currentUserSubject.next(user);
return user;
}));
}
logout() {
sessionStorage.removeItem('firstName');
sessionStorage.removeItem('lastName');
sessionStorage.removeItem('id');
this.currentUserSubject.next(null);
}
In sidebar typescript:
ngOnInit() {
this.firstName = JSON.parse(sessionStorage.getItem('firstName'));
this.lastName = JSON.parse(sessionStorage.getItem('lastName'));
}
In sidebar HTML:
<p>Welcome {{firstName}} {{lastName}}</p>
I want the sessionStorage to remove the previous details as soon as the user logs out. And next user's name to be displayed as soon as the user logs in. It should not display name on page refresh after entering the page.
It has to do with the ngOninit for the sidebar component. If this is initialised before the storage is set, it will never get a value. Same goes for logging out. The this.firstName value is never updated. What you could do is create a behaviorsubject which returns the user fields and is filled on initialisation or when the user is logging in.
This is the most logical fix for your problem given the code you've provided.
EDIT: Checking more of your code, you already have the subject to subscribe on (currentUserSubject). So if you subscribe to this in your sidebar component it should work.
EDIT 2:
In the authenticationService you have the currentUserSubject subject (i’d change this to a behavoirSubject, will explain later). This has the logged in user for the application. By subscribing to this behaviorSubject you’ll always have the newest value available in the places you subscribe. So also the sidebar component. Upon logging out, you just emit a new empty value to currentUserSubject. This will then clear the sidebar component values.
Upon initialisation of your application you could read your local storage and emit that to your behaviourSubject. This will ensure that if the localstorage is set, the sidebar has it’s values.
The code you will use upon loggin in is behaviorSubject.next(uservalue) and for logging out you could use behaviorSubject.next(null). Then wherever you subscribe you just check wether uservalue is present and handle it accordingly.
The reason to use a behaviorSubject instead of a subject has to do with holding values. The behaviourSubject has to be created with a initial value and will always emit the latest value, while a subject only emits all the values after you’ve subscribed to it.
EDIT 3: Here is the code example
export class AuthService {
private authenticatedUser = new BehaviorSubject<User>(undefined);
constructor(private http: HttpClient) {
this.initSubject();
}
public getAuthenticatedUser = this.authenticatedUser.asObservable();
private initSubject(): void {
if (hasLocalStorage) {
// Fill yourself :) Here you check if there is data in the localStorage
this.authenticatedUser.next(localStorage); // Here you pass in the localstorage data in the same format the login method does.
} else {
this.authenticatedUser.next(undefined);
}
}
login(username: string) {
return this.http
.post<any>(`${environment.api}/users/authenticate`, { username })
.pipe(
map((user) => {
sessionStorage.setItem('firstName', JSON.stringify(user.firstName));
sessionStorage.setItem('lastName', JSON.stringify(user.lastName));
sessionStorage.setItem('id', JSON.stringify(user.id));
this.authenticatedUser.next(user);
return user;
})
);
}
public logOut(): void {
this.authenticatedUser.next(undefined);
// And clear local storage
}
}
export class SidebarComponent implements OnInit {
public firstName: string = '';
public lastName: string = ''
constructor(private authService: AuthService) {}
ngOnInit() {
this.authService.getAuthenticatedUser.subscribe((user) => {
if (user) {
// set firstname and lastname
this.firstName = user.firstName;
this.lastName = user.lastName;
} else {
// not logged in
}
});
}
}

How to check and store whether user is logged in correctly?

Is there a better way of checking whether a user is logged in? Because I use the following approach for multiple apps and serving them somehow causes disparities, since it confuses the current app's item with other app's items.
I check whether a user is logged in like this:
constructor(private afAuth: AngularFireAuth, private router: Router, private db: AngularFirestore) {
this.userData = new ReplaySubject<UserDetails>();
afAuth.auth.onAuthStateChanged(user => {
if (user) {
this.user = user;
const local = localStorage.getItem('user');
if (local !== null) {
this.userData.next(JSON.parse(localStorage.getItem('user')));
} else {
this.fetchUserData();
}
} else {
localStorage.setItem('user', null);
}
});
}
get isLoggedIn(): boolean {
const user = localStorage.getItem('user');
return user !== 'null';
}
If each app is served from its own domain, then each will have its own localStorage and there can't be any conflict/confusion between them.
If you're serving multiple apps from the same domain, you'll have to use a unique name in the local storage for each app. Something like localStorage.setItem('app1_user', null) vs localStorage.setItem('app2_user', null).
But note that Firebase Authentication only has a single authenticated user per domain. So if you're serving multiple apps from the same domain, the user is (according to Firebase Authentication) signed in to all of them (or to none of them) at the same time.

Auth guard with observable?

Okay suppose I have auth guard.
I want to do just a simple thing: send request to backend, in case it sends me user info that means user is authenticated, I want to return true. Else it will send me the error, so I want to catch that error and redirect user.
How do I do it in with rxjs? It seems overcomplicated...
What I want to do is to check whether user is logged in and whether his token is valid. So I understand that I need to send a request but how to manager error or response in general then? I understand too, that if there is no token in local storage, I should return false and shouldn't even send any request.
Of course this doesn't work but I don't know how to do it at all...
// guard
return this.authService.checkUserAuthenticated();
// service
checkUserAuthenticated() {
this.http.post(`${this.domainName}api/auth/userinfo`, null)
.subscribe(
(data) => true,
(err) => false
);
}
you can make an api call to the backend using authguard then return true or false
export class AuthGuard implements CanActivate {
constructor(private router: Router, private service:Service) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
this.service.Authenticate().subscribe(
(data: any)=>{ any condition to check and then return true},
(error: any)=>{ return false;});
}
}
and add authguard authentication method to the routing file.

How am i supposed to use a Auth0 with a RESTful api?

I'm thinking about using Auth0 to signin my users on my nodejs API.
I'm using a MySQL database to sign them in and i also want to use Facebook so they can register and login.
I'm having an issue with the concept of callback, because my API is not supposed to be accessed via a browser. Only a webapp or a mobile app is supposed to access it. How do i have to implement the handling of my signin/login form inputs on my mobile app to use my API which is supposed to use Auth0 ?
Thank you for your answers.
Auth0 comes with a database on the free account. When you add the login registration widget to your application and a user signs up it adds them to the database in your auth0 account.
You can see information about the process here
What I do is authenticate users with the auth0 widget. This allows auth0 to handle encryption and security. Then when a user logs in i request a profile in the response. Typically this gives me at least basic info like an email address. I create my own database using the email address as a unique key which allows me to serve the correct data to the user when they login.
Here is an example of my auth0 service using a widget and requesting the user's profile in the response then storing it to local storage.
import { Injectable } from '#angular/core';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
import { Router } from '#angular/router';
import { myConfig } from './auth.config';
declare var Auth0Lock: any;
var options = {
theme: {
logo: '/img/logo.png',
primaryColor: '#779476'
},
languageDictionary: {
emailInputPlaceholder: "email#example.com",
title: "Login or SignUp"
},
};
#Injectable()
export class Auth {
lock = new Auth0Lock(myConfig.clientID, myConfig.domain, options, {});
userProfile: Object;
constructor(private router: Router) {
this.userProfile = JSON.parse(localStorage.getItem('profile'));
this.lock.on('authenticated', (authResult: any) => {
localStorage.setItem('access_token', authResult.idToken);
this.lock.getProfile(authResult.idToken, (error: any, profile: any) => {
if (error) {
console.log(error);
return;
}
localStorage.setItem('profile', JSON.stringify(profile));
this.userProfile = profile;
this.router.navigateByUrl('/overview');
});
this.lock.hide();
});
}
public login() {
this.lock.show();
}
private get accessToken(): string {
return localStorage.getItem('access_token');
}
public authenticated(): boolean {
try {
var jwtHelper: JwtHelper = new JwtHelper();
var token = this.accessToken;
if (jwtHelper.isTokenExpired(token))
return false;
return true;
}
catch (err) {
return false;
}
}
public logout() {
localStorage.removeItem('profile');
localStorage.removeItem('access_token');
this.userProfile = undefined;
this.router.navigateByUrl('/home');
};
}