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

@@ -1,45 +0,0 @@
import { LogLevel, type OpenIdConfiguration } from 'oidc-client-rx';
import type { ValueOf } from 'type-fest';
export const AuthMethodEnum = {
BASIC: 'basic',
OIDC: 'oidc',
} as const;
export type AuthMethodType = ValueOf<typeof AuthMethodEnum>;
export const AppAuthMethod = process.env.AUTH_TYPE as AuthMethodType;
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

@@ -1,4 +1,13 @@
import { AuthService } from '@/domains/auth/auth.service';
import { AUTH_PROVIDER, type AuthProvider } from '@/infra/auth/auth.provider';
import { BasicAuthProvider } from '@/infra/auth/basic';
import {
AUTH_METHOD,
type AuthMethodType,
getAppAuthMethod,
} from '@/infra/auth/defs';
import { OidcAuthProvider, buildOidcConfig } from '@/infra/auth/oidc';
import { UnreachableError } from '@/infra/errors/common';
import type { Injector, Provider } from '@outposts/injection-js';
import type { AnyRouter } from '@tanstack/react-router';
import {
@@ -9,16 +18,11 @@ import {
} from 'oidc-client-rx';
import { withTanstackRouter } from 'oidc-client-rx/adapters/@tanstack/react-router';
import type { Observable } from 'rxjs';
import {
AppAuthMethod,
AuthMethodEnum,
type AuthMethodType,
buildOidcConfig,
} from './config';
export function provideAuth(router: AnyRouter): Provider[] {
const providers: Provider[] = [AuthService];
if (AppAuthMethod === AuthMethodEnum.OIDC) {
const appAuthMethod = getAppAuthMethod();
if (appAuthMethod === AUTH_METHOD.OIDC) {
providers.push(
...provideOidcAuth(
{
@@ -32,18 +36,25 @@ export function provideAuth(router: AnyRouter): Provider[] {
withCheckAuthResultEvent()
)
);
providers.push({
provide: AUTH_PROVIDER,
useClass: OidcAuthProvider,
});
} else if (appAuthMethod === AUTH_METHOD.BASIC) {
providers.push({
provide: AUTH_PROVIDER,
useClass: BasicAuthProvider,
});
} else {
throw new UnreachableError(`Unsupported auth method: ${appAuthMethod}`);
}
return providers;
}
export function setupAuthContext(injector: Injector) {
const { authService } = authContextFromInjector(injector);
authService.setup();
}
export interface AuthContext {
type: AuthMethodType;
authService: AuthService;
authProvider: AuthProvider;
isAuthenticated$: Observable<boolean>;
userData$: Observable<{}>;
checkAuthResultEvent$: Observable<CheckAuthResultEventType>;
@@ -51,11 +62,18 @@ export interface AuthContext {
export function authContextFromInjector(injector: Injector): AuthContext {
const authService = injector.get(AuthService);
const authProvider = injector.get(AUTH_PROVIDER);
return {
type: AppAuthMethod,
authService,
type: authProvider.authMethod,
isAuthenticated$: authService.isAuthenticated$,
userData$: authService.userData$,
checkAuthResultEvent$: authService.checkAuthResultEvent$,
authService,
authProvider,
};
}
export function setupAuthContext(injector: Injector) {
const { authService } = authContextFromInjector(injector);
authService.setup();
}

View File

@@ -1,19 +1,17 @@
import type { RouterContext } from '@/infra/routes/traits';
import { runInInjectionContext } from '@outposts/injection-js';
import { autoLoginPartialRoutesGuard } from 'oidc-client-rx';
import { firstValueFrom } from 'rxjs';
import { authContextFromInjector } from './context';
export const beforeLoadGuard = async ({
context,
}: { context: RouterContext }) => {
const { isAuthenticated$ } = authContextFromInjector(context.injector);
const { isAuthenticated$, authProvider } = authContextFromInjector(
context.injector
);
if (!(await firstValueFrom(isAuthenticated$))) {
const guard$ = runInInjectionContext(context.injector, () =>
autoLoginPartialRoutesGuard()
const isAuthenticated = await firstValueFrom(
authProvider.autoLoginPartialRoutesGuard()
);
const isAuthenticated = await firstValueFrom(guard$);
if (!isAuthenticated) {
throw !isAuthenticated;
}

View File

@@ -26,9 +26,9 @@ export function useAuth() {
);
return {
...authContext,
userData,
injector,
isAuthenticated,
authContext,
};
}