Authentication in Angular 2, handling the observables

家住魔仙堡 提交于 2020-01-02 20:11:18

问题


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.


回答1:


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();
}



回答2:


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



来源:https://stackoverflow.com/questions/37062171/authentication-in-angular-2-handling-the-observables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!