Authentication in Angular 2, handling the observab

2019-05-30 04:05发布

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:

  • Create a custom RouterOutlet class (extending it) to handle the authentication logic whenever a url is called.

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.

2条回答
劫难
2楼-- · 2019-05-30 04:53

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

查看更多
姐就是有狂的资本
3楼-- · 2019-05-30 04:57

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();
}
查看更多
登录 后发表回答