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

如何基于Auth0示例应用配置Angular Universal SSR及解决升级报错

Angular 15 + Auth0 v2.0.1 SSR部署Heroku启动报错解决方案

问题描述

升级Angular到15版本、Auth0到v2.0.1后,带SSR的Angular应用部署到Heroku启动报错。编译无问题,但在依赖注入阶段将AuthService注入自定义包装类时触发location is not defined错误。已用isPlatformBrowser和isPlatformServer隔离浏览器相关代码,升级前逻辑正常,且错误仅发生在构造/依赖注入阶段,而非调用AuthService方法时。

错误日志

ERROR ReferenceError: location is not defined
at AuthService.shouldHandleCallback (...\server\main.js:1:4215732)
at new AuthService (...server\main.js:1:4213627)
at Object.AuthService_Factory [as factory] (...\server\main.js:1:4216049)    
at R3Injector.hydrate (...\server\main.js:1:2376384)
at R3Injector.get (...\server\main.js:1:2374606)
at injectInjectorOnly (...\server\main.js:1:2257584)
at Object.ɵɵinject (...\server\main.js:1:2257754)
at Object.Auth0Wrapper_Factory [as factory] (...\server\main.js:1:160425)    
at R3Injector.hydrate (...\server\main.js:1:2376384)
at R3Injector.get (...\server\main.js:1:2374606)

问题重现步骤

  • 在Auth0控制台创建SPA类型Angular应用
  • 下载示例应用,执行npm install并升级Angular CLI
  • 添加Universal SSR:ng add @nguniversal/express-engine
  • 修改server.ts中express导入方式后,执行npm run prerender触发window is not defined错误

解决方案

一、代码配置调整

1. 延迟初始化Auth0客户端

避免服务在服务器端初始化时访问浏览器API,仅在浏览器环境下初始化Auth0客户端:

// auth.service.ts
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Auth0Client } from '@auth0/auth0-spa-js';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private auth0Client: Auth0Client | null = null;

  constructor(@Inject(PLATFORM_ID) private platformId: object) {}

  async initAuth0Client() {
    if (isPlatformBrowser(this.platformId) && !this.auth0Client) {
      this.auth0Client = new Auth0Client({
        domain: '你的Auth0域名',
        client_id: '你的客户端ID',
        redirect_uri: `${window.location.origin}/callback`
      });
    }
  }

  async handleCallback() {
    await this.initAuth0Client();
    if (this.auth0Client) {
      await this.auth0Client.handleRedirectCallback();
    }
  }

  // 其他Auth0相关方法需先调用initAuth0Client
}

2. 调整包装类注入逻辑

自定义包装类Auth0Wrapper避免在构造函数中执行依赖浏览器API的逻辑,移到组件初始化阶段:

// auth0-wrapper.service.ts
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { AuthService } from './auth.service';
import { isPlatformBrowser } from '@angular/common';

@Injectable({ providedIn: 'root' })
export class Auth0Wrapper {
  constructor(
    private authService: AuthService,
    @Inject(PLATFORM_ID) private platformId: object
  ) {}

  async init() {
    if (isPlatformBrowser(this.platformId)) {
      await this.authService.initAuth0Client();
      // 此处处理回调等逻辑
    }
  }
}

在AppComponent的ngOnInit中调用Auth0Wrapper.init(),而非服务构造函数。

3. Server.ts适配处理

拦截Auth0回调路由,直接返回客户端应用让浏览器处理:

// server.ts
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';

const app = express();
const distFolder = join(process.cwd(), 'dist/your-app/browser');

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModule,
}));

app.set('view engine', 'html');
app.set('views', distFolder);

app.get('*.*', express.static(distFolder, {
  maxAge: '1y'
}));

// 拦截回调路由,交由客户端处理
app.get('/callback', (req, res) => {
  res.sendFile(join(distFolder, 'index.html'));
});

app.get('*', (req, res) => {
  res.render('index', { req, providers: [
    { provide: APP_BASE_HREF, useValue: req.baseUrl }
  ]});
});

二、Auth0控制台配置

1. 应用核心配置

  • 确认应用类型为Single Page Application
  • 在「Application URIs」中添加:
    • 允许的回调URL:https://你的Heroku域名/callback、http://localhost:4200/callback(本地开发)
    • 允许的注销URL:https://你的Heroku域名/、http://localhost:4200/
    • 允许的Web Origins:https://你的Heroku域名、http://localhost:4200

2. 本地开发环境配置

  • Hosts文件修改:
    Windows路径:C:\Windows\System32\drivers\etc\hosts;macOS/Linux路径:/etc/hosts,添加一行:127.0.0.1 local.your-app.com
  • 自签名证书生成(Auth0要求回调地址为HTTPS):
    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes
    
  • Angular本地启动配置:
    ng serve --ssl --ssl-key key.pem --ssl-cert cert.pem --host local.your-app.com --port 4200
    
  • 在Auth0控制台添加https://local.your-app.com:4200/callback到允许的回调URL和Web Origins。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:40:22