0

我在 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 构造函数中,身份服务器用户被分配给属性用户。

身份验证服务.ts

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

该方法唯一要做的isLoggedIn()就是检查user对象是否为空。令我惊讶的是它是 null :( 即使我们最近在 authservice 的构造函数中设置了它的值

    isLoggedIn(): boolean{
        return this.user != null && !this.user.expired;
    }

问题

然后这导致了我们著名的无限循环(KMN)。您也可以建议一个链接,因为很多人都遇到过这个问题,如果该链接对我有用,我会告诉您

4

1 回答 1

0

我设法从 GitHub 的 @brockallen 获得了一些帮助。

我所做的只是去那里sessionStorage取回用户。不再有无限循环

    isLoggedIn(): boolean{
        this.user = JSON.parse(sessionStorage.getItem("oidc.user")) as User;
        return this.user != null && !this.user.expired;
    }
于 2021-03-19T12:34:47.490 回答