refactor: refactor webui

This commit is contained in:
2025-04-26 01:43:23 +08:00
parent b20f7cd1ad
commit ee1b1ae5e6
104 changed files with 934 additions and 827 deletions

View File

@@ -0,0 +1,27 @@
import { InjectionToken } from '@outposts/injection-js';
import type { CheckAuthResultEventType } from 'oidc-client-rx';
import { type Observable, map } from 'rxjs';
import type { AuthMethodType } from './defs';
export abstract class AuthProvider {
abstract authMethod: AuthMethodType;
abstract checkAuthResultEvent$: Observable<CheckAuthResultEventType>;
abstract isAuthenticated$: Observable<boolean>;
abstract userData$: Observable<any>;
abstract getAccessToken(): Observable<string | undefined>;
abstract setup(): void;
abstract autoLoginPartialRoutesGuard(): Observable<boolean>;
getAuthHeaders(): Observable<Record<string, string>> {
return this.getAccessToken().pipe(
map((accessToken) =>
accessToken
? {
Authorization: `Bearer ${accessToken}`,
}
: ({} as Record<string, string>)
)
);
}
}
export const AUTH_PROVIDER = new InjectionToken<AuthProvider>('AUTH_PROVIDER');

View File

@@ -0,0 +1,22 @@
import { UnreachableError } from '@/infra/errors/common';
import type { CheckAuthResultEventType } from 'oidc-client-rx';
import { NEVER, type Observable, of } from 'rxjs';
import { AuthProvider } from '../auth.provider';
import { AUTH_METHOD } from '../defs';
export class BasicAuthProvider extends AuthProvider {
authMethod = AUTH_METHOD.BASIC;
isAuthenticated$ = of(true);
userData$ = of({});
checkAuthResultEvent$: Observable<CheckAuthResultEventType> = NEVER;
getAccessToken(): Observable<string | undefined> {
return of(undefined);
}
setup(): void {}
autoLoginPartialRoutesGuard(): Observable<boolean> {
throw new UnreachableError('Basic auth should always be authenticated');
}
}

View File

@@ -0,0 +1 @@
export { BasicAuthProvider } from './basic-auth.provider';

View File

@@ -0,0 +1,12 @@
import type { ValueOf } from 'type-fest';
export const AUTH_METHOD = {
BASIC: 'basic',
OIDC: 'oidc',
} as const;
export type AuthMethodType = ValueOf<typeof AUTH_METHOD>;
export function getAppAuthMethod(): AuthMethodType {
return process.env.AUTH_TYPE as AuthMethodType;
}

View File

@@ -0,0 +1,35 @@
import { LogLevel, type OpenIdConfiguration } from 'oidc-client-rx';
export function buildOidcConfig(): OpenIdConfiguration {
const origin = window.location.origin;
const resource = process.env.OIDC_AUDIENCE!;
return {
authority: process.env.OIDC_ISSUER!,
redirectUrl: `${origin}/auth/oidc/callback`,
postLogoutRedirectUri: `${origin}/`,
clientId: process.env.OIDC_CLIENT_ID!,
clientSecret: process.env.OIDC_CLIENT_SECRET,
scope: process.env.OIDC_EXTRA_SCOPES
? `openid profile email offline_access ${process.env.OIDC_EXTRA_SCOPES}`
: 'openid profile email offline_access',
triggerAuthorizationResultEvent: true,
responseType: 'code',
silentRenew: true,
useRefreshToken: true,
logLevel: LogLevel.None,
autoUserInfo: !resource,
renewUserInfoAfterTokenRenew: !resource,
customParamsAuthRequest: {
prompt: 'consent',
resource,
},
customParamsRefreshTokenRequest: {
resource,
},
customParamsCodeRequest: {
resource,
},
};
}

View File

@@ -0,0 +1,2 @@
export { buildOidcConfig } from './config';
export { OidcAuthProvider } from './oidc-auth.provider';

View File

@@ -0,0 +1,41 @@
import { injectInjector } from '@/infra/di/inject';
import { inject, runInInjectionContext } from '@outposts/injection-js';
import {
CHECK_AUTH_RESULT_EVENT,
OidcSecurityService,
autoLoginPartialRoutesGuard,
} from 'oidc-client-rx';
import { type Observable, map } from 'rxjs';
import { AuthProvider } from '../auth.provider';
import { AUTH_METHOD } from '../defs';
export class OidcAuthProvider extends AuthProvider {
authMethod = AUTH_METHOD.OIDC;
oidcSecurityService = inject(OidcSecurityService);
checkAuthResultEvent$ = inject(CHECK_AUTH_RESULT_EVENT);
injector = injectInjector();
setup() {
this.oidcSecurityService.checkAuth().subscribe();
}
get isAuthenticated$() {
return this.oidcSecurityService.isAuthenticated$.pipe(
map((s) => s.isAuthenticated)
);
}
get userData$() {
return this.oidcSecurityService.userData$.pipe(map((s) => s.userData));
}
getAccessToken(): Observable<string | undefined> {
return this.oidcSecurityService.getAccessToken();
}
autoLoginPartialRoutesGuard() {
return runInInjectionContext(this.injector, () =>
autoLoginPartialRoutesGuard()
);
}
}