【问题标题】:Angular 4: Observable not workingAngular 4:可观察到的不起作用
【发布时间】:2017-12-19 10:23:27
【问题描述】:

我正在使用的应用程序通过 Angular 2+ 的 adal.js 端口实现 Azure Active Directory 授权,效果很好。

我们有一个AuthenticationGuard 来处理与我们自己的AdalService 之间的调用。 AdalService 有一个函数ensureAuthenticatedAsync 检查用户是否登录,如果没有,将他重定向到 AD 登录页面。

我们现在有了新的要求,即当没有可用的 AD 帐户时,我们可以使用自定义生成的令牌进行登录。经过一些修改,我的代码如下所示:

authentication.guard.ts

public canActivate(route: ActivatedRouteSnapshot, state RouterStateSnapshot) : boolean {
    ...
    let params = route.queryParams;
    let token = (params !== null && params['token'] !== undefined) ? params['token'] : null;

    this.adalService.ensureAuthenticatedAsync(token);
    ...
    return true;
}

adal.service.ts

private context: adal.AuthenticationContext;

public ensureAuthenticatedAsync(token: string | null = null) {
    console.log('ensureAuthenticatedAsync', token);
    this.isAuthenticated.subscribe(isAuthenticated => {
        if (!isAuthenticated) {
            console.log('not authenticated);
            if (token === null) {
                // forward to AAD login page -> this works perfectly
                this.context.login();
            } else {
                ...
                console.log('accessToken before', this.accessToken);
                this.customToken = token;
                console.log('accessToken after', this.accessToken);
                ...
            }
        }
    });
}

public get accessToken(): string {
    console.log('customToken in get accessToken', this.customToken);
    return (this.customToken === null) ? this.context.getCachedToken(this.adalClientId) : this.customToken;
}

public get isAuthenticated(): Observable<boolean> {
    console.log('accessToken in get isAuthenticated', this.accessToken);
    let isAuthenticated: boolean = (this.accessToken !== null);
    return Observable.of(isAuthenticated);
}

app.component.ts

public ngOnInit(): void {
    this.adalService.isAuthenticated.subscribe(isAuthenticated => {
        if (isAuthenticated) {
            // do some stuff here
        }
    });
}

app.routes.ts

export const ROUTES: Routes = [
    { path: 'Dashboard', component: DashboardComponent, canActivate: [AuthenticationGuard] },
    { path: 'Access-Denied', component: AccessDeniedComponent }
];

这是控制台中记录的内容:

authentication guard  
customToken in get accessToken null  
accessToken in get isAuthenticated null  
customToken in get accessToken null  
ensureAuthenticatedAsync 12345  
not authenticated  
customToken in get accessToken null  
accessToken before null  
customToken in get accessToken 12345  
accessToken after 12345  
customToken in get accessToken 12345

定期访问页面 (http://localhost:3000/Dashboard) 会正确触发重定向到 AD 登录页面,然后在登录后返回到我的应用程序。在那里,缓存的 AD 令牌被更改,并且 isAuthenticated 在订阅的任何地方都被触发(在我的例子中是 app.component.ts )。

但是,使用令牌 (http://localhost:3000/Dashboard/?token=12345) 访问页面不起作用。即使 customToken 使用参数中的值进行了修改,更改似乎也不会传播,并且 isAuthenticated 将 false 保留在订阅中。

我错过了什么吗?

【问题讨论】:

  • 能否添加app.component.ts的相关代码以及customToken如何修改的例子?顺便说一句,isAuthenticated 返回一个 observable 似乎很奇怪,因为其中没有异步任务。
  • 我添加了 app.component.ts 中的代码,我订阅了该属性。 customToken 在 adal.service.ts 中被修改(this.customToken = token)。
  • 作为可观察对象:在此之前我有一个简单的布尔属性,从 adal 登录返回时它没有刷新值。我尝试了一个可观察的并且有效。
  • 您能否添加您的路由配置和带有自定义令牌的路由示例,以了解如何调用身份验证保护?
  • 我在 app.routes.ts 中添加了两个条目的示例,一个带有 AuthenticationGuard,另一个不带有 AuthenticationGuard。另外,我最后更改了描述以添加更多详细信息,包括路线示例。

标签: angular observable


【解决方案1】:

我认为问题在于守卫本地化。

你的守卫在 /Dashboard 路线上。因此,如果您仅加载 http://localhost:3000/?token=12345 您的 AuthenticationGuard 不会被调用,因此也不会调用 ensureAuthenticatedAsync 。所以你没有重定向,也没有更新 adal.service.ts 中的 customToken。

如果你想在 appComponent 中使用你守卫的计算结果,你必须在“领先”到 appComponent 的路线上使用守卫

编辑: 问题是您误解了反应行为。 isAuthenticated 的实现方式将发出一次布尔值,然后完成。所以你在 app.component 中的订阅只会触发一次。

您正在寻找的是行为主题,您可以在需要或 customToken 更改时“推送”新数据。

【讨论】:

  • 这是一个误解,实际上任何不匹配的路由都会重定向到/Dashboard。我在问题中的代码中添加了一些 console.logs,以向您展示我尝试过的内容以及它实际输出的内容。可以看到其实是更新了,但是没有触发isAuthorized,app.component.ts中的订阅也不知道发生了什么事。
  • 谢谢!这实际上有帮助。我切换到 BehaviorSubject 并完成了这项工作。
  • 抱歉,我只是不知道如何,因为实际答案在 cmets 中。不过,我将您的答案标记为正确,因为这就是我们的答案。
【解决方案2】:

试试:

在您的 adal.service.ts 中:

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
...
public get isAuthenticated(): Observable<boolean> {
 let isAuthenticated: boolean = (this.accessToken !== null);
 return of(isAuthenticated);
}

【讨论】:

  • 您介意解释一下应该有什么不同吗? return of(isAuthenticated)return Observable.of(isAuthenticated) 有什么不同?
  • 单独使用 rxjs 库可以通过仅使用必要的内容来优化产品构建。
  • 我们需要更多信息来调试这个脚本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2020-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多