我在 localhost:4200 上运行了一个 Angular 10 应用程序。在我的 app-routing.module.ts 中,我已经配置了加载 AdminComponent 的根路径,所以如果你点击 localhost:4200,它会尝试加载 AdminComponent,但在加载之前;我有一个 authguardservice 来检查用户是否登录,如果没有;它将用户重定向到身份服务器(他在其中获取登录屏幕以获取令牌)。
我无法控制身份服务器提供商,它由另一家公司托管
通过代码流和 PKCE 连接到 IdentityServer4。
我对这个问题进行了一些研究,很多人都面临同样的问题。但是我找不到适合我的解决方案。可能是因为我是 Angular 和 oidc 的新手?
https://github.com/damienbod/angular-auth-oidc-client/issues/180
https://github.com/damienbod/angular-auth-oidc-client/issues/829
调用signinRedirect时的Oidc-client无限循环
这是我的设置
应用程序路由.module.ts
const routes: Routes = [
{ path: 'signout-callback', component: SignoutRedirectCallbackComponent },
{ path: '', component: AdminComponent, canActivate: [AuthGuardService] },
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuardService],
runGuardsAndResolvers: 'pathParamsChange',
resolve: { client: ClientResolver },
children: [
{
path: 'dashboard',
component: DashboardComponent,
resolve: {
client: ClientResolver
}
}
]
},
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes, {scrollPositionRestoration: 'top'})],
exports: [RouterModule]
})
export class AppRoutingModule { }
auth-guard.service.ts
@Injectable()
export class AuthGuardService implements CanActivate{
constructor(private authService:AuthService) { }
canActivate():boolean{
if(this.authService.isLoggedIn()) {
return true;
}
this.authService.startAuthentication();
return false;
}
}
auth.service.ts
@Injectable({
providedIn: 'root'
})
export class AuthService{
private userManager: any;
private user: User = null;
constructor(){
this.userManager = new UserManager(this.getClientSettings());
this.userManager.getUser().then(user =>{
this.user = user;
});
}
isLoggedIn(): boolean{
return this.user != null && !this.user.expired;
}
getClaims(): any{
return this.user.profile;
}
getAuthorizationHeaderValue(): string{
return `${this.user.token_type}${this.user.access_token}`;
}
startAuthentication(): Promise<void>{
return this.userManager.signinRedirect();
}
completeAuthentication(): Promise<void>{
return this.userManager.signinRedirectCallback().then(user =>{
this.user = user;
});
}
public logout(): Promise<void>{
return this.userManager.signoutRedirect();
}
completeLogout(){
this.user = null;
return this.userManager.signoutRedirectCallback();
}
public getUser() : Promise<User>{
return this.userManager.getUser();
}
getUserToken(){
this.userManager.getUser().then(user => {
if(!!user && !user.expired){
console.log(`User : ${user.profile}`);
return user.access_token;
}else{
return null;
}
});
}
getAccessToken(): string {
this.userManager.getUser().then(user =>{
if(!!user && !user.expired){
return user.access_token;
}
});
return this.user.access_token;
}
LoginRedirectHandler(): Promise<any> {
console.log("LoginRedirectHandler");
return this.userManager.getUser().then((user) => {
// avoid page refresh errors
if (user === null || user === undefined) {
return this.userManager.signinRedirectCallback(null);
}
});
}
getClientSettings() : UserManagerSettings{
return {
authority: `${environment.authority}`,
client_id: environment.clientId,
client_secret: environment.clientSecret,
redirect_uri: `${environment.clientRoot}assets/signin-callback.html`,
automaticSilentRenew: true,
silent_redirect_uri: `${environment.clientRoot}assets/silent-callback.html`,
post_logout_redirect_uri: `${environment.clientRoot}signout-callback`,
response_type: 'code',
response_mode: 'query',
scope: environment.clientScope,
filterProtocolClaims: true,
loadUserInfo: false
}
}
}
当我在 localhost:4200 上运行应用程序时,我立即被重定向到身份服务器,这很好。输入电子邮件和密码,然后身份服务器重定向到 signin-callback.html 页面
用户对象有一个 id_token 值,您可以在下面的截图中看到。这也很好

在开发人员工具的网络选项卡中,我可以在响应部分看到令牌,请参阅下面的截图。所以到目前为止一切都很好

同样在我的 auth.service.ts 构造函数中,身份服务器用户被分配给属性用户。
这里的问题:
在身份服务器进行身份验证并将用户发回给我们之后,signin-callback.html 页面然后路由到“/admin”,在这里,authguardservice 再次运行并尝试通过调用isLoggedIn()方法检查用户是否登录的 authservice 。(如下所示)

该方法唯一要做的isLoggedIn()就是检查user对象是否为空。令我惊讶的是它是 null :( 即使我们最近在 authservice 的构造函数中设置了它的值
isLoggedIn(): boolean{
return this.user != null && !this.user.expired;
}
然后这导致了我们著名的无限循环(KMN)。您也可以建议一个链接,因为很多人都遇到过这个问题,如果该链接对我有用,我会告诉您


