身份验证问题 - 可观察量和承诺的执行顺序(Angular / REST)



我使用 Angular 7。

我是角度的新手,在我工作的机构,我们将创建一个新的角度应用程序。

我的一位同事创建了后端(Restful),我从身份验证功能开始。 因此,首先我们有一个带有顶栏和侧边栏的布局,它们在每个屏幕上。

完成布局后,我从登录组件开始,我还创建了一个 JWT 拦截器,以将令牌附加到任何标头。 并创建了一个AuthGuard来保护大多数路径。

我添加了一个具有登录,注销和经过身份验证功能的身份验证服务。

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 的提交表单中调用 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 的用户的获取时间太长,并且导航到"/dashboard"之前发生过。 之后,AuthGuard 试图获取身份验证服务的当前用户,但它仍然不存在,所以我被踢回"/login"并必须再次登录。 在我被踢到"/login"之后,当前用户在 AuthGuard 服务中设置,但现在为时已晚,我无法订阅它,因为它在第一次调用时未定义。

我试图在身份验证服务的登录功能中让用户进入管道,但它不起作用。

我期望的结果是,我按下登录按钮,设置当前用户(使用 ID 从 API 获取用户(因为用户对象非常大,不应该完全响应身份验证请求))

我被导航到/dashboard,在顶部栏中我可以看到我的用户名。

但在隐藏中,AuthGuard 应该监视用户是否经过身份验证,如果没有导航到/login。

页面刷新后,我想保持登录状态

我希望你们能理解我的意思,如果不是随意问。 如果需要,我可以附加一些代码行或显示其他组件。

使用 RxJS 的方式存在几个问题。不应以这种方式覆盖可观察变量。

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

最新更新