如何在验证访问令牌之前,在angular-oauth2-oidc中强制进行静默登录尝试?

huangapple go评论59阅读模式
英文:

How to force a silent login attempt before validationg the access token in angular-oauth2-oidc

问题

我正在使用angular-oauth2-oidc进行身份验证。它已配置为使用第三方SSO身份提供者。我的应用程序的设置遵循https://github.com/jeroenheijmans/sample-angular-oauth2-oidc-with-auth-guards。IdP没有实现会话状态更改通知,但我需要知道用户在我的站点和IdP之间来回导航时是否注销或更改。因此,我希望每次页面加载时都使用prompt=none重复进行身份验证请求,即使在sessionStorage中有未过期的访问令牌。我尝试更改runInitialLoginSequence并在检查oauthService.hasValidAccessToken()之前执行oauthService.silentRefresh(),但这导致无休止的循环。

所以我的问题是,在这种设置中,触发每次加载页面时使用prompt=none的身份验证请求的正确方法是什么?

英文:

I'm using angular-oauth2-oidc for authentication. It's configured to use a 3rd partry SSO identity provider. The setup of my app follows https://github.com/jeroenheijmans/sample-angular-oauth2-oidc-with-auth-guards. The IdP doesn't implement Session Status Change Notifications, but I need to know if the user logs out or changes while navigating back and forth between my site and the IdP. So I'd like repeat the authentication request with prompt=none every time the page loads, even if there is a non-expired access token in sessionStorage. I tried changing runInitialLoginSequence and executing oauthService.silentRefresh() before checking oauthService.hasValidAccessToken() but that leads to an endless loop.

So my question is what is the correct way to trigger an authentication request with prompt=none every time my page loads in this setup?

答案1

得分: 1

Scenario 1: "page load" means "SPA load"

I reckon that if you change the runInitialLoginSequence to merely remove the hasValidAccesstoken check, then that should do the trick. Then the silentRefresh runs each time the APP_INITIALIZER runs (so every time your SPA is freshly loaded).

The canActivateProtectedRoutes$ observable will not emit any value until both isDoneLoading$ (the login sequence being done) emits, and the isAuthenticated$ emits (which by default it always does, as it's a BehaviorSubject with a default of `false).

The guards will wait until isDoneLoading$ emits, which won't happen until the silentRefresh has completed.

Scenario 2: "page load" also means "Angular Route Change"

So if you also want the silent refresh to do a check each time the route changes, you'll have to do extra modifications.

In this case, you'll need to modify the guards and/or use Angular's Router events to trigger the silent refresh and make sure everyone waits until it has completed.

A straightforward (though perhaps not optimal or pretty) way to do it would be to change the AuthGuard (the one without forced login) to something like this:

canActivate(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
): Observable<boolean> {
  return this.authService.waitForNewSilentRefreshCallToBeCompleted$ // << Changed
    .pipe(map(_ => this.authService.canActivateProtectedRoutes$) // << Changed
    .pipe(tap(x => console.log('You tried to go to ' + state.url + ' and this guard said ' + x)));
}

Note that the // << Changed lines are pseudo-code; you'll have to implement something like that on the service yourself. It's not already in the sample.

英文:

**Scenario 1: "page load" means "SPA load"

I reckon that if you change the runInitialLoginSequence to merely remove the hasValidAccesstoken check then that should do the trick. Then the silentRefresh runs each time the APP_INITIALIZER runs (so every time your SPA is freshly loaded).

The canActivateProtectedRoutes$ observable will not emit any value until both isDoneLoading$ (the login sequence being done) emits, and the isAuthenticated$ emits (which by default it always does, as it's a BehaviorSubject with a default of `false).

The guards will wait until isDoneLoading$ emits, which won't happen until the silentRefresh has completed.

Scenario 2: "page load" also means "Angular Route Change"

So if you also want the silent refresh to do a check each time the route changes, you'll have to do extra modifications.

In this case you'll need to modify the guards and/or use Angular's Router events to trigger the silent refresh, and make sure everyone waits until it has completed.

A straightforward (though perhaps not optimal or pretty) way to do it would be to change the AuthGuard (the one without forced login) to something like this:

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot,
  ): Observable&lt;boolean&gt; {
    return this.authService.waitForNewSilentRefreshCallToBeCompleted$ // &lt;&lt; Changed
      .pipe(map(_ =&gt; this.authService.canActivateProtectedRoutes$) // &lt;&lt; Changed
      .pipe(tap(x =&gt; console.log(&#39;You tried to go to &#39; + state.url + &#39; and this guard said &#39; + x)));
  }

Note that the // &lt;&lt; Changed lines are pseudo-code, you'll have to implement something like that on the service yourself. It's not already in the sample.

huangapple
  • 本文由 发表于 2023年4月4日 17:17:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75927603.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定