配置是开发者生活的一部分。配置数据是你的应用程序运行所需的信息,可能包括第三方系统的令牌或你传递给库的设置。在Angular中,有不同的方式来加载配置数据作为应用程序初始化的一部分。你对配置数据的要求可能会根据需求而改变。例如,你的应用程序可能有一个不变的配置,或者你可能需要基于应用程序运行环境的不同配置。我们将介绍几种不同的方法来加载配置值,并确定何时应该使用每种方法。
我们将介绍使用Angular的具体用例,所以这篇文章假定你有一些开发Angular应用的经验。如果你有兴趣了解更多关于建立你的第一个Angular应用程序的信息,请查看Angular入门文档或指导你将Okta集成到Angular应用程序的教程链接。
在这篇文章中,我们将介绍以下几种形式的配置:
- 直接在代码中定义配置
- 为不同的环境定义配置
- 通过API调用加载配置数据
我们将展示每种方法的例子,包括如何与Okta集成。此外,我们还将确定何时使用每种技术以及需要注意的事项。
目录
在一个示例项目中设置Angular和Okta
首先,我们将设置基本项目和Okta资源,这样你就可以跟着帖子走了。
为了保持公平竞争,避免任何新的Angular功能的滑稽行为,我将在代码样本中使用Angular v9应用程序。所有概述的方法都适用于从Angular v7到目前的版本,即Angular v13。
创建Angular应用程序
你需要一个适用于你要创建的Angular应用版本的Node和npm。
我使用Node v14.18.1和npm v6.14.15来创建Angular v9应用程序,但你可以为你喜欢的Angular v7以上版本创建应用程序。
使用你在全球范围内安装的Angular CLI来创建一个带有路由和标准CSS的Angular应用,通过运行来进行样式设计。
ng new async-load --routing --style=css
或者通过运行以下命令来创建Angular v9应用程序。
npx @angular/cli@9 new async-load --routing --style=css
创建Okta应用程序
让我们创建Okta资源,以拥有我们需要整合的配置值。
在你开始之前,你需要一个免费的Okta开发者账户。安装Okta CLI并运行okta register ,注册一个新账户。如果你已经有一个账户,运行okta login 。然后,运行okta apps create 。选择默认的应用程序名称,或根据你的需要进行更改。 选择单页应用程序,然后按回车键。
在重定向URI中使用http://localhost:4200/login/callback ,并将注销重定向URI设置为http://localhost:4200 。
Okta CLI是做什么的?
Okta CLI将在您的Okta组织中创建一个OIDC单页应用。它将添加您指定的重定向URI并授予Everyone组的访问权限。它还会为http://localhost:4200 添加一个受信任的来源。当它完成时,你会看到如下的输出。
Okta application configuration:
Issuer: https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6
注意:你也可以使用Okta管理控制台来创建你的应用程序。更多信息请参见创建一个Angular应用程序。
我们将需要Okta Angular和Okta Auth JS库。通过运行以下命令将它们添加到您的应用程序中。
npm install @okta/okta-angular@5.1 @okta/okta-auth-js@6.0
这篇文章不会指导你设置签入和签出;我们只对设置配置感兴趣。如果Angular应用程序运行时没有错误,说明配置方面是正确的。要看到我们试图避免的错误类型,尝试排除issuer ,或者不要用你从Okta CLI得到的值替换{yourOktaDomain} 。示例代码 repo确实集成了签入和签出,所以你可以看到认证工作的全部过程。
在代码中定义配置
当你的配置是静态的,配置库的最直接方法是直接在代码中定义配置。在这种方法中,你会在AppModule ,或者在这个方法的功能模块中定义配置数据。这种方法的例子可能看起来像定义路由的配置并将其传入RouterModule 。
const routes: Routes = [
{ path: 'profile', component: ProfileComponent }
];
@NgModule({
declarations: [ AppComponent, ProfileComponent ],
imports: [
BrowserModule,
RouterModule.forRoot(routes)
],
bootstrap: [AppComponent]
})
export class AppModule { }
你可能会惊讶地看到路由作为直接在代码中定义配置的一个例子。 然而,当你把应用范围内的配置传入模块的forRoot() 静态方法时,这正是你在做的事情。
如果你跟随我们的许多代码例子和博客文章,将Okta集成到Angular应用程序中,你会遵循类似的模式,即配置直接在应用程序中定义。
你的配置代码看起来是这样的。
import { OktaAuthModule, OKTA_CONFIG } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
const oktaAuth = new OktaAuth({
issuer: '/oauth2/default',
clientId: '{yourClientId',
redirectUri: window.location.origin + '/login/callback'
});
@NgModule({
declarations: [ AppComponent, ProfileComponent ],
imports: [
BrowserModule,
AppRoutingModule,
OktaAuthModule
],
providers: [
{ provide: OKTA_CONFIG, useValue: { oktaAuth } }
],
bootstrap: [AppComponent]
})
export class AppModule { }
在代码中定义配置的总结。
当配置不因外部因素而改变时,这是向你的应用程序添加配置的最直接的方式。
什么时候使用。
- 尽可能多地使用,因为这是最简单的配置方式。
最佳用例。
- 静态的应用配置
- 配置第三方库
- 快速测试
要注意的是。
- 涉及私钥或令牌的配置
因环境而改变的配置
Angular有一个内置的方法来支持每个环境的差异,使用environments/environment.*.ts 文件。当本地服务时,Angular CLI使用environments/environment.ts 中的值,而当你为生产构建时,Angular CLI会替换成environment.prod.ts 。你可以在angular.json 构建配置中看到这种文件替换的定义。如果你有更多的环境需要支持,你可以自定义构建配置以满足你的需求。
当你有不同的配置想在构建时支持时,环境文件是有帮助的。一些例子包括只在prod环境中启用用户分析,或定义QA环境调用的API端点。
src/main.ts 包含一个根据环境改变配置的例子。在这里你可以看到以下内容。
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
Angular利用环境文件来确定何时调用enableProdMode() 方法。注意从./environments/environment 的文件导入。这是因为构建过程处理了该文件的交换。
现在让我们看看在与Okta集成时我们如何使用这个。
在src/environments/environment.ts ,像这样添加Okta auth配置。
export const environment = {
production: false,
authConfig: {
issuer: '/oauth2/default',
clientId: '{yourClientId}'
}
};
在src/environments/environment.prod.ts ,你将添加同样的authConfig 属性,其值与你的prod环境一致。
你将使用环境文件来初始化AppModule 中的OktaAuthModule ,像这样。
import { OktaAuthModule, OKTA_CONFIG } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
import { environment } from '../environments/environment.ts';
const oktaAuth = new OktaAuth({
...environment.authConfig,
redirectUri: window.location.orgin + '/login/callback'
});
@NgModule({
declarations: [ AppComponent, ProfileComponent ],
imports: [ BrowserModule, AppRoutingModule, OktaAuthModule ],
providers: [
{ provide: OKTA_CONFIG, useValue: { oktaAuth }}
],
bootstrap: [AppComponent]
})
export class AppModule { }
按环境变化的配置总结。
定制环境文件是Angular推荐的方法,可以在构建时注入数值。
何时使用。
- 你有基于构建输出的不同配置值
最佳用例。
- Devmode--让本地提供服务的应用不做只有prod应用才应该做的事情
- 多个暂存环境系统
要注意的是。
- 涉及私钥或令牌的配置
- 为每个环境运行构建,以测试你所做的改变。你不想错过添加一个属性,并有可能得到一个运行时错误。
从外部API加载配置
有时你需要在运行时加载配置。如果你使用发布推广式的部署,这就很有意义了--为暂存/预生产环境创建一个构建,并在验证后将同一构建推广到生产环境。你不想创建一个新的构建,但如果你的暂存环境和生产环境需要不同的配置怎么办?在这样的情况下,从外部API加载配置是很方便的。
为了使这种外部API配置方法保持简单,我将只关注Okta的例子。
在这个例子中,我们将看看src/main.ts ,在那里我们启动Angular应用程序。当你需要在应用加载前进行配置时,我们可以利用platformBrowserDynamic() 平台注入器的extraProviders 功能。extraProviders 允许我们提供平台提供者,这与我们在AppModule 中提供应用程序范围的提供者的方式相同。
由于我们需要在拥有完整的Angular应用程序上下文之前进行服务器调用以获得配置,所以我们使用Web APIs来调用API。然后我们可以为Okta的OKTA_CONFIG 注入令牌配置提供者。
对于一个配置API调用响应,看起来像这样。
{
"issuer": "/oauth2/default",
"clientId": "{yourClientId}",
"redirectUri": "{correctHostForTheEnvironment}/login/callback"
}
...你的src/main.ts 中的代码改为
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { OKTA_CONFIG } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
if (environment.production) {
enableProdMode();
}
fetch('http://{yourApiUri}/config').then(async res => {
const authConfig = await res.json();
platformBrowserDynamic([
{ provide: OKTA_CONFIG, useValue: {oktaAuth: new OktaAuth(authConfig)}}
]).bootstrapModule(AppModule)
.catch(err => console.error(err));
});
然后你的AppModule 只需要导入OktaAuthModule ,因为你已经提供了OKTA_CONFIG 的注入令牌。
如果你需要以编程方式创建回调URI,或者你需要在多个地方使用配置,你可以把配置存储在应用程序中。我们最少需要的是一个保存配置的类,我们将在例子中展示这个类。如果你的需求比我们在这里展示的更多,你可以把配置包裹在一个服务中。
你将添加一个新文件,并创建一个与响应相匹配的接口,以及一个容纳配置的类。
export interface AuthConfig {
issuer: string;
clientId: string;
}
export class OktaAuthConfig {
constructor(public config: AuthConfig) { }
}
编辑src/main.ts ,以代替提供OktaAuthConfig 类。
import { OktaAuthConfig } from './app/auth-config';
fetch('http://{yourApiUri}/config').then(async res => {
const authConfig = new OktaAuthConfig(await res.json());
platformBrowserDynamic([
{ provide: OktaAuthConfig, useValue: authConfig }
]).bootstrapModule(AppModule)
.catch(err => console.error(err));
})
在AppModule ,你可以通过访问OktaAuthConfig ,提供与Okta集成所需的OKTA_CONFIG 。
@NgModule({
declarations: [ AppComponent, ProfileComponent ],
imports: [
BrowserModule,
AppRoutingModule,
OktaAuthModule
],
providers: [
{
provide: OKTA_CONFIG,
deps: [OktaAuthConfig],
useFactory: (oktaConfig: OktaAuthConfig) => ({
oktaAuth: new OktaAuth({
...oktaConfig.config,
redirectUri: window.location.origin + '/login/callback'
})
})
}
]
})
export class AppModule { }
你现在可以从API加载一个配置,并使用应用程序的位置。
你可能会问自己,"不是有一个APP_INITIALIZER token或其他东西可以代替我们使用吗"?嗯,是的,有一个APP_INITIALIZER token,用于执行在应用初始化完成之前完成的初始化功能。然而,在我们的例子中,我们需要auth配置才能初始化。所以,我们需要在初始化应用之前完成配置的加载,这一点我们可以在启动时进行。
从外部API加载配置的总结
从API加载配置,并将配置提供给应用程序。根据你的需要,配置加载可以在启动过程中进行,也可以通过APP_INITIALIZER 。
何时使用
- 你希望配置在运行时加载,而不是被烘烤到代码中去
- 你的配置属性包括你不想提交给源代码控制的私人信息
最佳用例
- 你有不同的配置用于staging和prod,并使用release-promotion风格的部署流程
- 你的配置经常改变,或者经常改变,以至于构建和部署应用程序不可行。
注意以下情况
- 配置错误或网络突发事件--你的应用程序将无法运行,因为它依赖于外部API。
- 任何可能降低应用加载速度的情况,如过大的配置响应、调用过多的端点或缓慢的服务器响应。
- 验证和测试方面的潜在挑战,因为配置可能会改变。
了解更多关于Angular的信息
我希望这篇文章对你考虑如何将Okta整合到你的Angular应用中有所帮助。