Angular 带有身份服务器和 oidc-client-js 的 SPA:是否有一种模式可以在应用程序启动时触发登录(不使用登录按钮)?
Angular SPA with identity server and oidc-client-js: is there a pattern to trigger login when the application starts (without using a login button)?
我正在使用 angular 8 SPA,我正在尝试使用 oidc-client-js 库来处理用户身份验证。身份提供者是使用身份服务器4实现的。
我们期望的用户体验如下:当 SPA 在浏览器中加载时,不需要任何类型的用户交互,登录流程就会启动。换句话说,我们希望自动触发登录流程,避免在应用程序的第一个视图中使用显式登录按钮。
AppComponent
是我们应用程序中加载的第一个组件,它具有以下初始化方法:
ngOnInit() {
this.authService.login();
}
身份验证服务登录正在执行以下操作:
login() {
return this.userManager.signinRedirect();
}
通过这样做,我们能够成功地将用户重定向到身份服务器登录表单。提交登录表单后,身份服务器将用户重定向回配置的重定向 uri (/signin-callback
) 上的 SPA 应用程序。
那时我们想加载一个能够完成登录流程的组件。该组件应在其 ngOnInit
方法中调用身份验证服务的以下方法:
completeLogin() {
return this.userManager.signinRedirectCallback().then(user => {
console.log("Login has been completed.", user);
return user;
});
}
不幸的是,这种方法 不 工作,因为当身份服务器重定向回 SPA 应用程序时(提交登录表单后),AppComponent
被加载到浏览器和登录流程再次启动,无限重定向循环开始,直到浏览器最终崩溃。
我们有什么办法可以做到这一点吗?
补充说明:
- 我找到的所有示例都使用了明确的登录按钮,所以我问自己我们想要的行为是否有意义
- 核心问题是当应用程序在浏览器中启动时,我们总是调用
this.userManager.signinRedirect()
;如果登录流程 已经启动并且应用程序由于用户在身份服务器级别 登录后的重定向而正在加载,我们应该找到一种方法来避免调用。有可靠的方法吗?
2020 年 9 月 15 日更新
我发现处理此问题的最简单方法是在 static HTML 页面 内执行 sigin 重定向回调,即 不是 angular 应用程序的一部分。你可以找到一个例子 in the sample folder of the oidc client js repository
要求
完成这项工作有两个主要方面。它真的是一种设计模式,可以用任何语言实现:
- 根据您是否可以从 API 获取数据来触发登录重定向
- 将登录响应作为页面加载的一部分进行处理,然后使令牌可用于调用 API,避免进一步重定向
您必须了解 Angular 的细节,因为我不知道该框架。我希望这能给你一些有用的建议。
我的资源
下面的代码使用纯 Typescript,您需要将其转换为您首选的 Angular 语法。
Code to get an access token。请注意,getAccessToken 函数会触发登录重定向。
Code to load the page。请注意作为页面加载的一部分对 handleLoginResponse 的调用
Code to deal with access token expiry。请注意,在到期时会触发新的登录重定向。
Blog Post 有关初始 OIDC 客户端集成的更多详细信息
我的博客还有一些更高级的示例(如果有用的话),例如静默令牌更新 - 以及 Quick Start Page 您可以在其中 运行 具有上述行为的在线 React 示例。
在你的 auth.service 中你可能有类似这两个函数的东西:
private checkUser = (user : User): boolean => {
return !!user && !user.expired;
}
public isAuthenticated = (): Promise<boolean> => {
return this._userManager.getUser()
.then(user => {
if(this._user !== user){
this._loginChangedSubject.next(this.checkUser(user));
}
this._user = user;
return this.checkUser(user);
})
}
然后而不是调用
ngOnInit() {
this.authService.login();
}
你可以使用这个:
ngOnInit() {
this.authService.isAuthenticated().then((isAuthenticated) => {
if (!isAuthenticated) {
this.authService.login();
}
});
}
我正在使用 angular 8 SPA,我正在尝试使用 oidc-client-js 库来处理用户身份验证。身份提供者是使用身份服务器4实现的。
我们期望的用户体验如下:当 SPA 在浏览器中加载时,不需要任何类型的用户交互,登录流程就会启动。换句话说,我们希望自动触发登录流程,避免在应用程序的第一个视图中使用显式登录按钮。
AppComponent
是我们应用程序中加载的第一个组件,它具有以下初始化方法:
ngOnInit() {
this.authService.login();
}
身份验证服务登录正在执行以下操作:
login() {
return this.userManager.signinRedirect();
}
通过这样做,我们能够成功地将用户重定向到身份服务器登录表单。提交登录表单后,身份服务器将用户重定向回配置的重定向 uri (/signin-callback
) 上的 SPA 应用程序。
那时我们想加载一个能够完成登录流程的组件。该组件应在其 ngOnInit
方法中调用身份验证服务的以下方法:
completeLogin() {
return this.userManager.signinRedirectCallback().then(user => {
console.log("Login has been completed.", user);
return user;
});
}
不幸的是,这种方法 不 工作,因为当身份服务器重定向回 SPA 应用程序时(提交登录表单后),AppComponent
被加载到浏览器和登录流程再次启动,无限重定向循环开始,直到浏览器最终崩溃。
我们有什么办法可以做到这一点吗?
补充说明:
- 我找到的所有示例都使用了明确的登录按钮,所以我问自己我们想要的行为是否有意义
- 核心问题是当应用程序在浏览器中启动时,我们总是调用
this.userManager.signinRedirect()
;如果登录流程 已经启动并且应用程序由于用户在身份服务器级别 登录后的重定向而正在加载,我们应该找到一种方法来避免调用。有可靠的方法吗?
2020 年 9 月 15 日更新
我发现处理此问题的最简单方法是在 static HTML 页面 内执行 sigin 重定向回调,即 不是 angular 应用程序的一部分。你可以找到一个例子 in the sample folder of the oidc client js repository
要求
完成这项工作有两个主要方面。它真的是一种设计模式,可以用任何语言实现:
- 根据您是否可以从 API 获取数据来触发登录重定向
- 将登录响应作为页面加载的一部分进行处理,然后使令牌可用于调用 API,避免进一步重定向
您必须了解 Angular 的细节,因为我不知道该框架。我希望这能给你一些有用的建议。
我的资源
下面的代码使用纯 Typescript,您需要将其转换为您首选的 Angular 语法。
Code to get an access token。请注意,getAccessToken 函数会触发登录重定向。
Code to load the page。请注意作为页面加载的一部分对 handleLoginResponse 的调用
Code to deal with access token expiry。请注意,在到期时会触发新的登录重定向。
Blog Post 有关初始 OIDC 客户端集成的更多详细信息
我的博客还有一些更高级的示例(如果有用的话),例如静默令牌更新 - 以及 Quick Start Page 您可以在其中 运行 具有上述行为的在线 React 示例。
在你的 auth.service 中你可能有类似这两个函数的东西:
private checkUser = (user : User): boolean => {
return !!user && !user.expired;
}
public isAuthenticated = (): Promise<boolean> => {
return this._userManager.getUser()
.then(user => {
if(this._user !== user){
this._loginChangedSubject.next(this.checkUser(user));
}
this._user = user;
return this.checkUser(user);
})
}
然后而不是调用
ngOnInit() {
this.authService.login();
}
你可以使用这个:
ngOnInit() {
this.authService.isAuthenticated().then((isAuthenticated) => {
if (!isAuthenticated) {
this.authService.login();
}
});
}