angular2检查用户是否经过身份验证

时间:2016-06-17 14:31:27

标签: angular

我已经坚持了几天,并且需要一些帮助/指导,以便检查用户是否在我的angular-rc1应用中进行了身份验证。

我从我的服务器获取一个令牌,并希望将其存储在本地存储中(除非有人更好地在应用程序中保留令牌)。我遇到的主要问题是,当令牌发生变化时,我无法检测到组件中的变化。

通过阅读大约20个SO帖子/文章,我想我发现最好的方法是在我的user.service.ts中创建一个observable并订阅我的组件中的observable,当用户更改时我需要检测他们的代币。

方法#1 BehaviorSubject - Delegation: EventEmitter or Observable in Angular2

import {BehaviorSubject} from 'rxjs/BehaviorSubject';

export class UserService {
  // Observable userToken source
  _userToken = new BehaviorSubject<string>("");

  // Observable userToken stream
  userToken$ = this._userToken.asObservable();

  // set the user token in a way that is observable for subscribed components
  setUserToken(token) {
    this._userToken.next(token);
  }

  ...
}

import {Subscription} from 'rxjs/Subscription';

export class NavBarComponent implements OnInit{
  subscription: Subscription;
  ...

  ngOnInit(){
    this.subscription = this._userService.userToken$.subscribe(
      userToken => {
        console.log('setting user token on navbar to ' + userToken);
        this.userToken = userToken
      });
  }
}

export class LoginComponent implements OnInit {
    ...

    ngOnInit() {
    /*
      Get the authentication code from twitch and then send that authentication
      code to the server. The server does stuff and then either passes back a
      200 with key token in data, or passes back an error 4xxx code.
    */
    var routeParams:any = this._routeParams.params

    if(routeParams.code){
      this.isLoading = true;
      this._userService.authenticateTwitch(routeParams.code)
        .subscribe(resp => {
          this._userService.setUserToken(resp.key);
          this.isLoading = false;
          this._router.navigate(['Search']);
        });
    }
  }
}

好的,所以这个方法的问题是当LoginComponent触发this._userService.setUserToken(resp.key)时,在NavbarComponent中看不到subscribe事件。初始化NavbarComponent时,会触发subscribe方法中的console.log,但是当LoginComponent中的令牌发生更改时,它不会执行任何操作。

我对方法#1感觉非常好,我认为这是正确的方法。这只是因为某些原因订阅没有收到更改。

方法#2订阅LocalStorage更改 - How can I watch for changes to localStorage in Angular2?(以及问题中附带的plunker)

我在这里使用"angular2-localstorage": "^0.4.0"直接使用本地存储。我创建一个新服务来处理本地存储更改,然后在我的组件中订阅该Observable

export class StorageService {
  public userToken$: Observable<string>;
  private _userTokenObserver;
  private _userToken;

  constructor() {
    this._userToken = "";
    this.userToken$ = new Observable(observer => {
      this._userTokenObserver = observer;
    }).share();
  }

  add(value: string) {
    console.log('setting userToken to ' + value);
    this._userToken = value;
    this._userTokenObserver.next(this._userToken);
  }

  load() {
    this._userTokenObserver.next(this._userToken);
  }
}

    export class NavbarComponent {
        ...

        ngOnInit() {
          console.log('navbar init');
          this._storageService.userToken$.subscribe(latestUserToken => {
            console.log('subscribe fired on navbar with latest user token: ', latestUserToken);
            this.userToken = latestUserToken;
            console.log('user token on nav component is now: ', this.userToken);
          });

          this._storageService.load();
        }
    }

我的ngOnInit中也有类似的LoginComponent代码。这种方法很有意思,因为订阅有点适用于LoginComponent,但不适用于NavbarComponent

我说“有点”,因为我不认为订阅实际上有效。看起来NavbarComponent首先被初始化并且令牌没有准备好,而LoginComponent在令牌可用之后被初始化。如果令牌发生更改(例如注销并清除令牌),则订阅方法不会获取更改。

...至少在LoginComponent上!注销位于NavbarComponent,订阅事件在NavbarComponent上触发。因此,事件似乎只包含在发生事件的组件中,而不是共享给订阅该事件的所有组件。

navbar init
navbar.component.ts:34 subscribe fired on navbar with latest user token:  
navbar.component.ts:36 user token on nav component is now: 
login init
user.service.ts:31 authenticating against server with twitch token: aaaaa
storage.service.ts:19 setting userToken to bbbbb
login.component.ts:42 subscribe fired in login componenet with latest usertoken:  bbbbb login.component.ts:44 use
登录组件上的令牌现在是:bbbbbb

其他想法

我认为这些问题的一个可能原因是我的所有组件都是通过RouterOutlet呈现的,而我的NavbarComponent是直接在app.template.html中呈现的。但是,我尝试将导航栏移动到我的组件中,但它仍然具有相同的行为。

<!-- app.template.html -->
<hero-navbar></hero-navbar>
<router-outlet></router-outlet>

另一件事可能是订阅不应该进入ngOnInit函数。似乎代码运行一次,但之后不再运行。我认为问题更可能是潜在的观察者/订阅关系,但是...

如果您已经阅读了整篇文章,我向您表示祝贺,并深深感谢您花时间阅读本文,这是迄今为止我最长的帖子。如果我能提供更多信息以帮助提出如何解决此问题的建议,请告诉我。

1 个答案:

答案 0 :(得分:5)

我在angular2应用程序上遇到了同样的问题。我通过使用公共ApiService解决了这个问题,该公共ApiService将所需信息添加到请求(即授权标头)。调用我的API的其他服务从此服务扩展。

当用户登录时,我将令牌保存在本地存储中并设置属性&#39; isAuthenticated&#39;在我的AppState上为true。我还将该属性传递给app.component.html中的标题。这样,只要用户登录/退出,您的标题就会自动更新。

app.component.ts:

constructor(public appState: AppState) {
  appState.state.isAuthenticated = false;
}

app.component.html:

<navbar [isAuthenticated]="appState.state.isAuthenticated"></navbar>

navbar.component.ts:

@Input() isAuthenticated:boolean;

auth.service.ts:

 return this.http.post(this.baseUrl, body, { headers }).subscribe((result) => {
  localStorage.setItem('oauth', JSON.stringify(result.json()));
  this.appState.set('isAuthenticated', true);

  return result;
});

我希望这有帮助!