Angular 5 multiple Conditional Routing : "AuthGuards" - javascript

i am trying to create conditional routing in angular 5 and i have seen this post and the official milestone page of angular:
Angular2 conditional routing.
But i didn't find a way to create multiple conditions based on input variables.
here is my code :
import { Injectable } from '#angular/core';
import {CanActivate, Router, RouterStateSnapshot, ActivatedRouteSnapshot} from '#angular/router';
import {AuthServiceService} from './auth-service.service';
#Injectable()
export class AuthguardService implements CanActivate{
constructor(
private router: Router,
private AuthService:AuthServiceService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if(this.AuthService.ValidAs("User")!=true){
this.router.navigate(['pages/login']);
return false;
}else{
return true;
}
}
}
My AuthService.ValidAs() method takes an argument to determine the type of user to try and validate as rightful to access a route and returns a boolean. i have three types of users, how do i pass extra arguments to the canActivate property in my routes in order to use that as argument to my ValidAs method.
If there is any other way to create multiple canActivate instances without multiplying files, let me know.

You can pass a data object to any route like that:
...
{
path:'dashboard',
component:DashboardComponent,
canActivate:[
AuthGuard
],
data:{
roles: ['ROLE_ADMIN', 'ROLE_EDITOR', 'OTHER_ROLE'],
// any other relevant data to make your checks
}
},
...
Then in your AuthGuard you can retrieve the data like:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
...
const roles = route.data[ 'roles' ] as Array<string>;
// Do other checks here
...
}

You have two options.
First is to use params or queryParams.
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
const userType = router.paramMap.get('userType');
}
Second is to use the dependency injection.
constructor(
private router: Router,
private AuthService: AuthServiceService,
#Inject(CURRENT_USER) user: User,
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const userType = this.user.type;
}

Related

Using a variable as a firebase reference in angular

I would like to have a string variable contain a value and then use it to set a reference path to my firebase database. Ex. The uid will store the variable from the routed paramMap and then used in the path to fetch the data from the database. I tried this below but it obviously didn't work.
export class HistoryComponent implements OnInit {
snaps: Observable<any[]>;
uid: string;
constructor(db: AngularFireDatabase
private ngZone: NgZone, private afs: AngularFirestore, private route:
ActivatedRoute){
this.snaps = db.list('snapity-tests/12-02-19/'+ $(uid)).valueChanges();
}
ngOnInit() {
this.route.paramMap
.subscribe(params => {
this.uid = params.get('uid');
console.log(this.uid)
})
}}
You need to move your code inside the constructor to the ngOnInit lifecycle hook, because the class constructor is always called before the onInit hook.
As stated in the Angular Docs:
A lifecycle hook that is called after Angular has initialized all data-bound properties of a directive
So, you only need to subscribe to the route params, and then, when you have the value that you want, then you can use it:
export class HistoryComponent implements OnInit {
snaps: Observable<any[]>;
uid: string;
constructor(
private db: AngularFireDatabase,
private ngZone: NgZone,
private afs: AngularFirestore,
private route: ActivatedRoute
){ }
ngOnInit() {
this.route.paramMap
.subscribe(params => {
this.uid = params.get('uid');
this.snaps = db.list('snapity-tests/12-02-19/'+ this.uid).valueChanges();
})
}}

Why does the value not change to false in AuthGuard?

In the template component AppComponent, depending on the value, the variable this.loggedInService.isLoggedIn switches between the logIn() and logout() methods, which in the application component AppComponent are subscribed to these methods in the service LoggedinServiceand depending on the method, change the value of the variable to true or false.
Also in the Guard's method checkLogin (url: string) I return true or false depending on the value of the variable this.loggedInService.isLoggedIn.
When I start the application, I cannot enter the module, when I click on the button, I can, but when I repeat click on the button "exit", I can still go to the module.
How to make the switch to checkLogin work so that the authentication works correctly and save the value of switching the state between input and output when the page is restarted?
**AppComponent.html: **
<li class="nav-item">
<a class="btn btn-outline-success"
[class.btn-outline-success]="!this.loggedInService.isLoggedIn$"
[class.btn-outline-danger]="this.loggedInService.isLoggedIn$"
(click)="this.loggedInService.isLoggedIn$ ? logout() : logIn()">
{{this.loggedInService.isLoggedIn$ ? 'Exit' : 'Enter'}}
</a>
</li>
**AppComponent.ts **
export class AppComponent implements OnInit {
message: string;
constructor(public loggedInService: LoggedinService,
public router: Router) {
this.setMessage();
}
ngOnInit() {}
logIn(): void {
this.loggedInService.login().subscribe(() => {
if (this.loggedInService.isLoggedIn$) {
let redirect = this.loggedInService.redirectUrl ? this.loggedInService.redirectUrl :
'/gallery';
this.router.navigate([redirect]);
}
});
}
logout(): void {
this.loggedInService.logout();
}
}
LoggedinService:
export class LoggedinService {
isLoggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLoggedIn$: Observable<boolean> = this.isLoggedIn.asObservable();
redirectUrl: string;
constructor() {}
login(): Observable < boolean > {
return of(true).pipe(
delay(100),
tap(val => this.isLoggedIn.next(true))
);
}
logout(): void {
this.isLoggedIn.next(false);
}
}
AuthGuard:
export class AuthGuard implements CanActivate {
constructor(
private loggedInService: LoggedinService,
private router: Router
) {}
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
let url: string = state.url;
return this.loggedInService.isLoggedIn$;
}
checkLogin(url: string): boolean {
if (this.loggedInService.isLoggedIn) {
return true;
} else {
this.loggedInService.redirectUrl = url;
return false;
}
}
}
isLoggedIn in your LoggedinService is a Primitive Data type. So it is not passed by reference. It's passed by value. So if there is a change in it at one place, the same change won't reflect at other places where it is used.
This behavior is only exhibited by Objects as they are passed by reference and NOT value.
You could use a BehaviorSubject to fix this issue.
import { Injectable } from '#angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { Router } from '#angular/router';
import { delay, tap } from 'rxjs/operators';
#Injectable()
export class LoggedinService {
isLoggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLoggedIn$: Observable<boolean> = this.isLoggedIn.asObservable();
redirectUrl: string;
constructor(private router: Router) { }
login(): Observable<boolean> {
this.isLoggedIn.next(true);
return this.isLoggedIn$;
}
logout(): Observable<boolean> {
this.isLoggedIn.next(false);
return this.isLoggedIn$;
}
}
Now, instead of isLoggedIn of type boolean, you'll get isLoggedIn$ of type Observable which you'll have to subscribe to, to get the logged in status of the user.
You'll have to .subscribe to this.loggedInService.login() and this.loggedInService.login() in your AppComponent as both of them return isLoggedIn$. You'll have to create a local isLoggedIn property and assign it whatever is returned in your .subscribe. You can then set the button text and click handler based on the template based on this isLoggedIn property.
In the case, of AuthGuard, since a guard can return Observable<boolean> or Promise<boolean> or boolean, you can simply return this.loggedInService.isLoggedIn$
Here's a Sample StackBlitz for your ref.

How to disable users from accessing previous page by browser back button after logout in angular2?

I am trying not to allow users to go to previous page using browser back button after logout. I wish to show users a messge like "Please login to continue".in Angular 2
create a new file called authorization.guard.ts and add this
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import {AppContextService} from './context';
#Injectable()
export class AuthorizationGuard implements CanActivate {
constructor(
private appContextService:AppContextService
){}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
return this.appContextService.getAuthAdminLoggednIn();
}
}
later in your main module import {AuthorizationGuard}
add this in your each router path
{
path: 'dashboard',
canActivate:[AuthorizationGuard]
},
Refer this files for complete authorization
Refer this

How to add query params to route in guard and pass it to component in Angular 4?

I am using a route guard in my angular 4 app, and I would like to add a query param to the route if a condition satisfies and return true.
Here's the code I have been working on
#Injectable()
export class ViewGuardService implements CanActivate {
constructor(private router: Router) { }
canActivate(activatedRoute: ActivatedRouteSnapshot, snapshot: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if(!this.router.url.includes('/order-management')) {
//ADD PARAMS TO ROUTE OR PASS DATA TO COMPONENT HERE AND THEN RETURN TRUE
return true;
} else {
this.route.navigate['/login'];
return false;
}
}
}
Usually, to navigate to a route with params we can use it as this.router.navigate(['/order-management', activatedRoute.url[0].path], { queryParams: { moveToOrders: true }});. But if I use this condition in the if condition, it turns out to an infinite loop of function calls.
So how do I pass params or data from the guard to the component? Please help me resolve this issue.
This is a bit hacky, but it works (Angular 11).
#Injectable({
providedIn: 'root'
})
export class SetQueryParamGuard implements CanActivate {
constructor(
private _router: Router
) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> {
const requiredQueryParam = route.queryParamMap.get('requiredQueryParam');
// Query param is set, no further action
if (requiredQueryParam) {
return of(true);
}
return of(
this._router
.parseUrl(state.url + `&requiredQueryParam=DEFAULT_VALUE`)
);
}
}

Connect the authentication service with the AuthGuard (simple issue)

I guess it's quite simple issue, but unfortunately I don't really know how to deal with it.
I'm trying to connect my UserAuthenticationService service with the ActivationGuard.
UserAuthenticationService.ts:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
#Injectable()
export class UserAuthenticationService {
isUserAuthenticated: boolean = false;
username: string;
constructor(private http: Http) {
}
authentication() {
this.http.get(`http://localhost/api/auth/isLogged/${this.username}`)
.subscribe(res => { //^^returns true or false, depending if the user is logged or not
this.isUserAuthenticated = res.json();
},
err => {
console.error('An error occured.' + err);
});
}
}
ActivationGuard.ts
import {Injectable} from '#angular/core';
import {Router, RouterStateSnapshot, ActivatedRouteSnapshot} from '#angular/router';
import {Observable} from 'rxjs/Observable';
import {UserAuthenticationService} from './UserAuthenticationService';
interface CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean
}
#Injectable()
export class WorksheetAccessGuard implements CanActivate {
constructor(private router: Router, private userService: UserAuthenticationService) {
}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.userService) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
Note
It works great, if I just use localStorage to store the information if the user is logged or not:
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (!localStorage.getItem('currentUser')) {
this.router.navigate(['/']);
return false;
}
return true;
}
But how can I connect the service with the guard? Looking forward for any kind of help. Thank you in advance.
If you need any more information, please let me know and I will edit my post.
Call authentication() method of UserAuthenticationService either in constructor or On ngOnit then it sets the isUserAuthenticated variable and use that in the ActivationGuard.ts
UserAuthenticationService.ts:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
#Injectable()
export class UserAuthenticationService {
isUserAuthenticated: boolean = false;
username: string;
constructor(private http: Http) {
this.authentication();
}
authentication() {
this.http.get(`http://localhost/api/auth/isLogged/${this.username}`)
.subscribe(res => { //^^returns true or false, depending if the user is logged or not
this.isUserAuthenticated = res.json();
},
err => {
console.error('An error occured.' + err);
});
}
}
ActivationGuard.ts
#Injectable()
export class WorksheetAccessGuard implements CanActivate {
constructor(private router: Router, private userService: UserAuthenticationService) {
}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.userService.isUserAuthenticated) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
This is not the right approach for doing it. Every time you call the service , it initialize a new instance and hence you get a false.
You should create a singleton service instance ( via the main module in your app) - where it will contain your app state ( in memory / localstorage)
Then , when you'll call UserAuthenticationService - you won't update its owbn parameter but the main's one ( the singleton).
I suggest you to use a BehaviourSubject ( read about it , it's like a Subject but it also yields its last value without waiting to emit a value manually).
From that point your app can see from anywhere ig the user is logged in or not.

Categories

Resources