Angular UI 中的授权
Angular 应用模板已预先配置了 OAuth。因此,当你使用 CLI(或 Suite)启动项目时,授权功能已经就绪。ABP Angular UI 包使用 angular-oauth2-oidc 库来管理 Angular 客户端的 OAuth。 你可以在 environment.ts 文件中找到 OAuth 配置。
授权码流程
import { Config } from '@abp/ng.core';
const baseUrl = 'http://localhost:4200';
export const environment = {
// 为简洁起见,其他选项已省略
oAuthConfig: {
issuer: 'https://localhost:44305',
redirectUri: baseUrl,
clientId: 'MyProjectName_App',
responseType: 'code',
scope: 'offline_access MyProjectName',
},
// 为简洁起见,其他选项已省略
} as Config.Environment;
此配置实现了带有 PKCE 的 OAuth 授权码流程。 根据此流程,用户将被重定向到使用 MVC 构建的外部登录页面。因此,如果你需要自定义登录页面,请参考此社区文章。
资源所有者密码流程
如果你在项目中使用了 Angular UI 账户模块,可以通过修改 environment.ts 文件中的 OAuth 配置来切换到资源所有者密码流程,如下所示:
import { Config } from '@abp/ng.core';
export const environment = {
// 为简洁起见,其他选项已省略
oAuthConfig: {
issuer: 'https://localhost:44305',
clientId: 'MyProjectName_App',
dummyClientSecret: '1q2w3e*',
scope: 'offline_access MyProjectName',
},
// 为简洁起见,其他选项已省略
} as Config.Environment;
根据此流程,用户将被重定向到账户模块中的登录页面。
错误过滤
在 AuthFlowStrategy 类中,有一个名为 listenToOauthErrors 的方法,用于监听 OAuthErrorEvent 错误。该方法会清除 localStorage 中的 OAuth 密钥。但在某些情况下,我们可能希望跳过此过程。为此,我们可以使用 AuthErrorFilterService。
AuthErrorFilterService 是一个抽象服务,需要通过自定义实现来替换
默认情况下,此服务在
@abp/ng.oauth包中被替换
使用方法
1. 创建认证过滤器提供者
//auth-filter.provider.ts
import { inject, provideAppInitializer } from '@angular/core';
import { AuthErrorFilter, AuthErrorEvent, AuthErrorFilterService } from '@abp/ng.core';
import { eCustomersAuthFilterNames } from '../enums';
export const CUSTOMERS_AUTH_FILTER_PROVIDER = [
provideAppInitializer(() => {
configureAuthFilter()
}),
];
type Reason = object & { error: { grant_type: string | undefined } };
function configureAuthFilter() {
const errorFilterService = inject(
AuthErrorFilterService<AuthErrorFilter<AuthErrorEvent>, AuthErrorEvent>,
);
const filter: AuthErrorFilter = {
id: eCustomersAuthFilterNames.LinkedUser,
executable: true,
execute: (event: AuthErrorEvent) => {
const { reason } = event;
const {
error: { grant_type },
} = <Reason>(reason || {});
return !!grant_type && grant_type === eCustomersAuthFilterNames.LinkedUser;
},
};
return () => errorFilterService.add(filter);
}
AuthErrorFilter:是过滤器对象的模型,它具有 3 个属性id:列表中过滤器对象的唯一键executable:过滤器对象的状态。如果为 false,则不会执行,但仍保留在列表中execute:存储跳过逻辑的函数
2. 添加到客户配置提供者
// customer-config.provider.ts
import { EnvironmentProviders, makeEnvironmentProviders } from "@angular/core";
import { CUSTOMERS_AUTH_FILTER_PROVIDER } from "./auth-filter.provider";
export function provideCustomerConfig(): EnvironmentProviders {
return makeEnvironmentProviders([
CUSTOMERS_AUTH_FILTER_PROVIDER
])
}
现在,如果发生任何 OAuthErrorEvent,它将跳过清除 LinkedUser grant_type 的 OAuth 存储密钥
使用自定义实现替换
使用 AbstractAuthErrorFilter<T,E> 类作为处理过程的标识。
示例
my-auth-error-filter.service.ts
import { Injectable, signal } from '@angular/core';
import { MyAuthErrorEvent } from 'angular-my-auth-oidc';
import { AbstractAuthErrorFilter, AuthErrorFilter } from '@abp/ng.core';
@Injectable({ providedIn: 'root' })
export class OAuthErrorFilterService extends AbstractAuthErrorFilter<
AuthErrorFilter<MyAuthErrorEvent>,
MyAuthErrorEvent
> {
protected readonly _filters = signal<Array<AuthErrorFilter<MyAuthErrorEvent>>>([]);
readonly filters = this._filters.asReadonly();
get(id: string): AuthErrorFilter<MyAuthErrorEvent> {
return this._filters().find(({ id: _id }) => _id === id);
}
add(filter: AuthErrorFilter<MyAuthErrorEvent>): void {
this._filters.update(items => [...items, filter]);
}
patch(item: Partial<AuthErrorFilter<MyAuthErrorEvent>>): void {
const _item = this.filters().find(({ id }) => id === item.id);
if (!_item) {
return;
}
Object.assign(_item, item);
}
remove(id: string): void {
const item = this.filters().find(({ id: _id }) => _id === id);
if (!item) {
return;
}
this._filters.update(items => items.filter(({ id: _id }) => _id !== id));
}
run(event: MyAuthErrorEvent): boolean {
return this.filters()
.filter(({ executable }) => !!executable)
.map(({ execute }) => execute(event))
.some(item => item);
}
}
抠丁客


