我已经坚持了几天,并且需要一些帮助/指导,以便检查用户是否在我的angular-rc1应用中进行了身份验证。
我从我的服务器获取一个令牌,并希望将其存储在本地存储中(除非有人更好地在应用程序中保留令牌)。我遇到的主要问题是,当令牌发生变化时,我无法检测到组件中的变化。
通过阅读大约20个SO帖子/文章,我想我发现最好的方法是在我的user.service.ts
中创建一个observable并订阅我的组件中的observable,当用户更改时我需要检测他们的代币。
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感觉非常好,我认为这是正确的方法。这只是因为某些原因订阅没有收到更改。
我在这里使用"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
登录组件上的我认为这些问题的一个可能原因是我的所有组件都是通过RouterOutlet呈现的,而我的NavbarComponent是直接在app.template.html
中呈现的。但是,我尝试将导航栏移动到我的组件中,但它仍然具有相同的行为。
<!-- app.template.html -->
<hero-navbar></hero-navbar>
<router-outlet></router-outlet>
另一件事可能是订阅不应该进入ngOnInit
函数。似乎代码运行一次,但之后不再运行。我认为问题更可能是潜在的观察者/订阅关系,但是...
如果您已经阅读了整篇文章,我向您表示祝贺,并深深感谢您花时间阅读本文,这是迄今为止我最长的帖子。如果我能提供更多信息以帮助提出如何解决此问题的建议,请告诉我。
答案 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;
});
我希望这有帮助!