在 Angular 5 中,静默刷新不适用于 OIDC 客户端
Posted
技术标签:
【中文标题】在 Angular 5 中,静默刷新不适用于 OIDC 客户端【英文标题】:Silent refresh not working with OIDC-client in Angular 5 【发布时间】:2018-07-24 12:28:03 【问题描述】:我对@987654321@ 的静默刷新有疑问。
登录工作正常,我可以获得令牌。
但是,静默刷新不会触发,没有任何反应。当我订阅检查令牌过期的方法(下面的 authservice.ts 中的 subscribeevents
中的方法)时,这些方法永远不会触发 - 即使令牌已过期,方法 isLoggedIn()
也总是返回 true。
这是我的代码:
import Component, OnInit from '@angular/core';
import UserManager from 'oidc-client';
import getClientSettings from '../openIdConnectConfig';
import AuthService from '../services/auth.service';
@Component(
selector: 'app-silentrefresh',
templateUrl: './silentrefresh.component.html',
styleUrls: ['./silentrefresh.component.css']
)
export class SilentRefreshComponent implements OnInit
constructor(private _authService:AuthService)
ngOnInit()
this._authService.refreshCallBack();
然后是我的身份验证服务:
import UserManagerSettings, UserManager, User from 'oidc-client';
import Injectable from '@angular/core';
import getClientSettings from '../openIdConnectConfig';
@Injectable()
export class AuthService
private _manager = new UserManager(getClientSettings());
private _user: User = null;
constructor()
this._manager.getUser().then(user =>
this._user = user;
);
this._manager.events.addUserLoaded(user =>
this._user = user;
);
this.subscribeevents();
public isLoggedIn(): boolean
return this._user != null && !this._user.expired;
public getClaims(): any
return this._user.profile;
public subscribeevents(): void
this._manager.events.addSilentRenewError(() =>
console.log("error SilentRenew");
);
this._manager.events.addAccessTokenExpiring(() =>
console.log("access token expiring");
);
this._manager.events.addAccessTokenExpired(() =>
console.log("access token expired");
);
public refreshCallBack(): void
console.log("start refresh callback");
this._manager.signinSilentCallback()
.then(data => console.log("suucess callback") )
.catch(err =>
console.log("err callback");
);
console.log("end refresh callback");
getUser(): any
return this._user;
getName(): any
return this._user.profile.name;
getAuthorizationHeaderValue(): string
return `$this._user.token_type $this._user.access_token`;
startAuthentication(): Promise<void>
return this._manager.signinRedirect();
completeAuthentication(): Promise<void>
return this._manager.signinRedirectCallback().then(user =>
this._user = user;
);
还有我的配置:
import UserManagerSettings from "oidc-client";
export function getClientSettings(): UserManagerSettings
return
authority: 'https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679',
client_id: '257b6c36-1168-4aac-be93-6f2cd81cec43',
redirect_uri: 'http://localhost:4200/auth-callback',
//redirect_uri: 'https://demoazureadconnectangular5.azurewebsites.net/auth-callback',
post_logout_redirect_uri: 'http://localhost:4200/',
//post_logout_redirect_uri: 'https://demoazureadconnectangular5.azurewebsites.net/',
response_type: "id_token",
scope: "openid profile",
filterProtocolClaims: true,
loadUserInfo: true,
automaticSilentRenew: true,
silent_redirect_uri: 'http://localhost:4200/assets/silentrefresh',
metadata:
issuer: "https://sts.windows.net/136544d9-038e-4646-afff-10accb370679/",
authorization_endpoint: "https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679/oauth2/authorize",
token_endpoint: "https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679/oauth2/token",
//jwks_uri: "https://login.microsoftonline.com/common/discovery/keys",
jwks_uri: "http://localhost:4200/assets/keys.json",
//jwks_uri: "https://demoazureadconnectangular5.azurewebsites.net/assets/keys.json",
//jwks_uri: "http://localhost:50586/api/keys",
signingKeys: [ "ApiAccessKey": "NgixniZ0S1JHxo7GPEZYa38OBTxSA98AqJKDX5XqsJ8=" ]
;
我也尝试过使用这样的静态页面:
<head>
<title></title>
</head>
<body>
<script src="oidc-client.min.js"></script>
<script>
var usermanager = UserManager().signinSilentCallback()
.catch((err) =>
console.log(err);
);
</script>
</body>
它从来没有被解雇过
为了测试,我将 ID 令牌的有效期更改为 10 分钟。 我使用 Azure AD Connect(Azure 中的 Open Id Connect),微软表示它与 Open ID Connect 标准不完全兼容......所以我不知道它是在我这边还是在 Azure 那边。
有人可以帮我解决这个问题吗?
【问题讨论】:
找到解决方案了吗? 您找到解决方案了吗? 【参考方案1】:问题是您不是从 azure AD 询问 access_token,而只是 id_token。您必须将 response_type 设置为 id_token 令牌才能获取这两个令牌。这种变化还需要更多的参数。例如后端的资源。 我在这里回答了类似的问题。我也在使用 Angular 5 和 oidc 客户端。 https://***.com/a/50922730/8081009 我也在https://github.com/IdentityModel/oidc-client-js/issues/504#issuecomment-400056662之前在这里回答你 以下是您需要设置的内容才能让静默更新正常工作。
includeIdTokenInSilentRenew: true
extraQueryParams:
resource: '10282f28-36ed-4257-a853-1bf404996b18'
response_type: 'id_token token',
scope: 'openid'
loadUserInfo: false,
automaticSilentRenew: true,
silent_redirect_uri: `$window.location.origin/silent-refresh.html`,
metadataUrl: 'https://login.microsoftonline.com/YOUR_TENANT_NAME.onmicrosoft.com/.well-known/openid-configuration',
signingKeys: [
add here keys from link below
]
https://login.microsoftonline.com/common/discovery/keys
我还在使用不同的静态页面作为带有静默更新的回调端点,因为这样用户不会注意到任何事情。此页面尽可能小,因此 oidc 不会将整个 Angular 应用程序加载到隐藏的 iframe 中,它用于静默更新。所以建议这样更高效。
<head>
<title></title>
</head>
<body>
<script src="assets/oidc-client.min.js"></script>
<script>
new Oidc.UserManager().signinSilentCallback()
.catch((err) =>
console.log(err);
);
</script>
</body>
【讨论】:
我完全同意。但在 2 月,不支持 access_token,但在 azure AD 上 Open Is Connect。询问 access_token 会引发错误。现在它在隐式流中得到支持。就是这样。【参考方案2】:检查数据库中是否有正确的重定向 URI。
检查您是否在 angular.json
文件中添加了以下内容:
...
"assets": [
"src/assets",
"silent-refresh.html",
"oidc-client.min.js"
.....
],
...
查看silent-refresh.html
:
<script src="oidc-client.min.js"></script><script>
var mgr = new Oidc.UserManager();
mgr.signinSilentCallback().catch(error =>
console.error(error);
);
</script>
检查您创建的UserManager
实例不超过一个
您可以使用任何一种方式 - automaticSilentRenew: false
或 automaticSilentRenew: true,
我建议使用 automaticSilentRenew: false
并在到期时触发事件。
https://github.com/IdentityModel/oidc-client-js/wiki
public renewToken()
return this.manager.signinSilent().then(u =>
this.user = u;
).catch(er =>
console.log(er);
);
this.manager.events.addAccessTokenExpiring(x =>
console.log('Acess token expiring event');
this.renewToken().then(u =>
console.log('Acess token expiring event renew success');
);
);
如果上述方法不起作用,请检查身份服务器代码。
身份服务器代码
启动
services.AddIdentityServer(options =>
options.Authentication.CookieLifetime = TimeSpan.FromDays(30);
options.Authentication.CookieSlidingExpiration = true;
);
services.AddAuthentication(x => x.DefaultAuthenticateScheme = IdentityServerConstants.DefaultCookieAuthenticationScheme);
退出
await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme);
感谢https://github.com/IdentityModel/oidc-client-js/issues/911#issuecomment-617724445
【讨论】:
【参考方案3】:最简单的原因是,不在身份服务器配置中添加静默更新 url 作为重定向 url。
在您的身份服务器数据库中,您的客户端的重定向 url 应该是这样的
redirectUrls: [http://localhost:4200/assets/silentrefresh, http://localhost:4200/auth-callback]
【讨论】:
【参考方案4】:我使用了一些不同的方法来启动silentRenw,而不是使用
automaticSilentRenew: true,
我决定显式调用 signInSilent();。 这样做的原因我遇到了一些问题,因为 automaticSilentRenew: true,没有按预期工作。
我在实现我的接口的 UserAuth 类构造函数中初始化了事件和方法
constructor(private oidcSettings: CoreApi.Interfaces.Authentication.OpenIDConnectionSettings)
this.userManager.events.addAccessTokenExpiring(() =>
this.userManager.signinSilent(scope: oidcSettings.scope, response_type: oidcSettings.response_type)
.then((user: Oidc.User) =>
this.handleUser(user);
)
.catch((error: Error) =>
//Work around to handle to Iframe window timeout errors on browsers
this.userManager.getUser()
.then((user: Oidc.User) =>
this.handleUser(user);
);
);
);
handleUser 只是检查登录用户。
因此,如果您在构造函数中初始化 signInSilent 进程,然后调用 signInSilent 完成,即回调它可能会起作用。
【讨论】:
谢谢,但是 addaccessTokenExpiring 永远不会触发......原因是:我从 Azure Ad 获得了 IdToken 而不是 AccessToken 哦,我明白了,在这种情况下,登录静默仅适用于 access_token。我希望 openID 连接流程是隐式还是授权流程? 隐式 (spa) 或基本(仅后端)。我无法使用 OIDC-Client 更新 ID 令牌,因为 Azure AD,最后一个不提供 access_token。与其他提供商我不知道,因为我从未尝试过 GLUU 或 OpenAM 等其他 IDP 提供商确实支持正确的 openID 流并返回 access_token 和 id_token。 我没有选择使用 azure AD【参考方案5】:Not sure what oidc-client.js version you are using, this should never have worked.
```
new Oidc.UserManager().signinSilentCallback()
.catch((err) =>
console.log(err);
);
``
Usermanager is in **Oidc** object.
【讨论】:
以上是关于在 Angular 5 中,静默刷新不适用于 OIDC 客户端的主要内容,如果未能解决你的问题,请参考以下文章
符号 ::after css,不适用于 Angular 5 的指令
Cordova 的插件(屏幕方向/应用程序版本)不适用于 Ionic 5 / Angular 11
angular 5 stepper selectedIndex 不适用于订阅中设置的变量