我使用Angular 7。
我对Angle并不陌生,在我工作的代理商中,我们将创建一个新的angular应用。
我的一个同事创建了后端(Restful),然后我开始使用身份验证功能。 因此,首先,我们在每个屏幕上都有一个带有顶部栏和侧栏的布局。
完成布局后,我从登录组件开始,还创建了一个JWT拦截器,将令牌附加到任何标头。 并创建了AuthGuard来保护大多数路径。
我添加了一个AuthenticationService,其功能为登录,注销和isAuthenticated。
export class AuthenticationService {
public currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
returnUrl: string;
constructor(private http: HttpClient, private userService: UserService, private router: Router, private route: ActivatedRoute) {
if (localStorage.getItem("currentUser")) {
const userId = JSON.parse(localStorage.getItem("currentUser")).id;
userService.getById(userId).subscribe((data) => {
this.currentUserSubject = new BehaviorSubject<User>(data as User);
this.currentUser = this.currentUserSubject.asObservable();
});
}
}
isAuthenticated() {
const authState = new Subject<boolean>();
this.currentUser.subscribe(data => {
console.log(data);
if (data) {
authState.next(true);
} else {
authState.next(false);
}
});
return authState.asObservable();
}
login(email: string, password: string) {
return this.http.post<any>(`http://pitchbook.localhost/authentication_token`, {
username: email,
password
})
.pipe(map(object => {
// login successful if there's a jwt token in the response
if (object.user && object.token) {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
const jsonObject = {
id: object.user.id,
token: object.token
};
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(jsonObject));
return jsonObject;
}
return object;
}));
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
this.currentUserSubject.next(null);
location.reload(true);
}
}
然后我以LoginComponent的Submit形式调用了login()。
onSubmit() {
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.authenticationService.login(this.loginF.email.value, this.loginF.password.value)
.pipe(first()).subscribe(
(object) => {
this.userService.getById(object.id as number).subscribe((data) => {
this.authenticationService.currentUserSubject.next(data as User);
this.authenticationService.currentUser = this.authenticationService.currentUserSubject.asObservable();
console.log(this.authenticationService.currentUser);
this.router.navigate(["/dashboard"]);
this.alertService.success("Success");
});
},
(error) => {
this.loading = false;
this.alertService.error("Error");
}
);
}
所以现在的问题是,当我登录ID为ID的User时,获取时间太长了,之前导航到“ / dashboard”就发生了。 之后,AuthGuard试图获取AuthenticationService的currentUser,但它仍然不存在,因此我被踢回了“ / login”并不得不再次登录。 在我被踢到“ /登录”之后,在AuthGuard服务中设置了currentUser,但是现在为时已晚,我无法订阅它,因为它在第一次调用时是未定义的。
我试图通过AuthenticationService的登录功能将User放入管道中,但是没有用。
我期望的结果是,我按下登录按钮,设置了currentUser(从具有ID的API中获取用户(因为用户对象很大,并且不应完全响应身份验证请求))
我转到/ dashboard,然后在顶部栏中看到我的用户名。
但是在隐藏状态下,如果未导航到/ login,则AuthGuard应该监视用户是否已通过身份验证。
页面刷新后,我想保持登录状态
我希望你们能理解我的意思,即使不是随意问。 如果需要,我可以添加一些代码行或显示其他组件。
答案 0 :(得分:0)
使用RxJS的方式存在几个问题。您不应以这种方式覆盖Observables变量。
在AuthenticationService
中以这种方式声明currentUser
:
public readonly currentUser = this.currentUserSubject.asObservable();
然后从onSubmit()
方法中删除以下内容。
this.authenticationService.currentUser = this.authenticationService.currentUserSubject.asObservable();
isAuthenticated
方法编写错误(泄漏订阅),一种更好的方法可能是:
isAuthenticated() {
return this.currentUser.pipe(map(user => !!user));
}