Reputation: 3915
I just started with a Angular 2 project and am trying to get authentication up and running. Inspired by this tutorial I decided to do the following:
I succeeded in this custom class, but am still not sure how to check if a user is authenticated. My situation is as follows, I need to query a get call to a external API, for my development proces it is as follows:
getAdmin() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get('http://localhost:3000/admin/is_admin.json', options)
.map(res => res)
.catch(this.handleError)
}
This API call returns true or false. I was wondering what would be the best option to use this information? Should I for example call the following function each time a URL should be checked?:
isAdmin() {
this.getAdmin().subscribe(
data => this.authenticationResult = data,
error => console.log("Error: ", error),
() => return JSON.parse(this.authenticationResult._data);
}
I can't get this up and running because my observable is undefined when using the function I gave as example.
Upvotes: 1
Views: 218
Reputation: 202266
The "problem" is that your method is asynchronous so you need to be careful the way and when you use it.
If you want to use within the activate
method of your custom RouterOutlet
, you need to leverage observables and reactive programming.
I don't know exactly the way you want to check admin roles:
activate(instruction: ComponentInstruction) {
return this.userService.getAdmin().flatMap((isAdmin) => {
if (this.userService.isLoggIn()) {
if (this._canActivate(instruction.urlPath, isAdmin) {
return Observable.fromPromise(super.activate(instruction));
} else {
this.router.navigate(['Forbidden']);
return Observable.throw('Forbidden');
}
} else {
this.router.navigate(['Login']);
return Observable.throw('Not authenticated');
}
}).toPromise();
}
_canActivate(url, admin) {
return this.publicRoutes.indexOf(url) !== -1
|| this.userService.isLoggedIn();
}
In order to optimize the request, you could lazily (and only once) call the request to check if the user is admin or not:
isAdmin:boolean;
getAdmin() {
if (this.isAdmin) {
return Observable.of(this.isAdmin);
} else {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get('http://localhost:3000/admin/is_admin.json', options)
.map(res => res)
.catch(this.handleError);
}
}
Another approach will be also to load this hint when authenticating the user. This way, the implementation of the activate
method would be simplier:
activate(instruction: ComponentInstruction) {
if (this.userService.isLoggIn()) {
if (this.userService.isAdmin()) {
return super.activate(instruction);
} else if (this._canActivate(instruction.urlPath, isAdmin) {
return super.activate(instruction);
} else {
this.router.navigate(['Forbidden']);
}
} else {
this.router.navigate(['Login']);
}
}
_canActivate(url, admin) {
return this.publicRoutes.indexOf(url) !== -1
|| this.userService.isLoggedIn();
}
Upvotes: 1
Reputation: 17762
I would consider to call getAdmin() somehow as first Step of your app, store the result in a SessionService object which you move around using Dependency Injection. This way any time you need to check the result of getAdmin you can ask the SessionService instance. I hope this helps
Upvotes: 0