You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中signinRedirect未定义及依赖注入错误排查

Angular认证服务两类错误的解决方案

错误说明

1. 初始依赖注入错误

Uncaught (in promise): Error: StaticInjectorError[PublicKeyService]

原因:PublicKeyService未在Angular模块的providers数组中注册,导致依赖注入机制无法找到该服务实例。

2. 路由守卫触发的空指针错误

Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'signinRedirect')

原因:AuthenticationSecureAuthService中的manager(UserManager实例)通过异步HTTP请求初始化,路由守卫AuthGuard调用startAuthentication()时,异步请求尚未完成,manager仍为undefined。


解决方案

1. 修复依赖注入错误

在你的Angular模块(如AppModule或对应功能模块)的providers数组中添加相关服务:

import { NgModule } from '@angular/core';
import { PublicKeyService } from './security/services/app.public-key-service';
import { AuthenticationSecureAuthService } from './security/services/authentication-secure-auth-service';
import { AuthGuard } from './security/services/auth.guard';

@NgModule({
  // ...其他模块配置
  providers: [
    PublicKeyService,
    AuthenticationSecureAuthService,
    AuthGuard
    // ...其他需要注册的服务
  ]
})
export class AppModule { }

2. 修复异步初始化导致的空指针错误

修改AuthenticationSecureAuthService,用BehaviorSubject跟踪manager的初始化状态,确保认证操作仅在实例就绪后执行:

修改后的AuthenticationSecureAuthService关键代码:

import {Injectable, OnDestroy} from '@angular/core';
// ...保留原导入
import {BehaviorSubject} from 'rxjs';
import {first} from 'rxjs/operators';

@Injectable()
export class AuthenticationSecureAuthService implements OnDestroy {
  private readonly loginReturnUrlKey: string = 'loginReturnUrlKey';
  private user: User = null;
  private manager: UserManager;
  // 用于跟踪manager是否初始化完成
  private managerReady$ = new BehaviorSubject<boolean>(false);

  constructor(
    private http: HttpClient, 
    private userService: UserService, 
    private router: Router,
    private publicKeyService: PublicKeyService
  ) {
    Oidc.Log.logger = console;
    Oidc.Log.level = Oidc.Log.INFO;
    this.publicKeyService.getClientSettings().subscribe(
      data => {   
        console.log(data);
        this.manager = new UserManager(data);
        this.start();
        // 标记manager初始化完成
        this.managerReady$.next(true);
      }
    );
  }

  // ...保留原其他方法

  startAuthentication(): Promise<void> {
    // 等待manager就绪后再执行跳转
    return this.managerReady$.pipe(
      first(isReady => isReady)
    ).toPromise().then(() => {
      return this.manager.signinRedirect();
    });
  }

  // ...保留原其他方法
}

修改AuthGuard的checkLoggedIn方法

由于startAuthentication()现在返回Promise,checkLoggedIn需要返回Promise<boolean>,让路由守卫等待异步操作完成:

private checkLoggedIn(url: string): Promise<boolean> {
  const loggedIn = this.userService.isLoggedIn();
  const sessionCurrent = this.userService.isSessionCurrent();
  if (loggedIn && sessionCurrent) {
    return Promise.resolve(true);
  }

  if (loggedIn && !sessionCurrent) {
    this.userService.clearCurrentUserAndToken();
    this.alertService.error('Your session has expired.', true);
  }

  if (url && url.charAt(0) !== '/') {
    url = '/' + url;
  }
  this.authService.setLoginReturnUrl(url);

  // 执行认证跳转后返回false
  return this.authService.startAuthentication().then(() => false);
}

同步更新canActivate和canLoad的返回类型:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
  return this.checkLoggedIn(state.url);
}

canLoad(route: Route): Promise<boolean> {
  console.log(route.path);
  return this.checkLoggedIn(route.path);
}

额外修复:PublicKeyService中的this指向问题

getClientSettings方法内的add_signing_keys函数使用普通函数导致this指向丢失,改成箭头函数保留实例上下文:

public getClientSettings() {
  const metadata = {
    issuer: `https://login.microsoftonline.com/${this.tenantId}/v2.0`,
    authorization_endpoint: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`,
    token_endpoint: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`
  };

  // 改成箭头函数,确保this指向PublicKeyService实例
  const add_signing_keys = (keys_array) => {
    return {
      metadata: metadata,
      singingKeys: keys_array,
      authority: `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`,
      client_id: `${environment.secureAuthClientId}`,
      redirect_uri: `${this.getBaseUrl()}/auth-callback`,
      post_logout_redirect_uri: this.getBaseUrl(),
      response_type: 'id_token',
      scope: 'openid profile email',
      filterProtocolClaims: true,
      loadUserInfo: false,
      automaticSilentRenew: false,
      checkSessionInterval: 1000000,
      userStore: new WebStorageStateStore({ store: sessionStorage })
    };
  };

  return this.http.get<{ keys }>(this.jwks_uri).pipe(
    map(val => add_signing_keys(val.keys))
  );
}

内容的提问来源于stack exchange,提问作者sreddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:35:30