mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
refactor: extracted auth as middleware to be added manually to endpoints
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { type AuthAction, Authenticator, type ProfileExchange, Role, type Strategy } from "auth";
|
||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||
import { Exception, type PrimaryFieldType } from "core";
|
||||
import { type DB, Exception, type PrimaryFieldType } from "core";
|
||||
import { type Static, secureRandomString, transformObject } from "core/utils";
|
||||
import { type Entity, EntityIndex, type EntityManager } from "data";
|
||||
import { type FieldSchema, entity, enumm, make, text } from "data/prototype";
|
||||
@@ -17,6 +17,7 @@ declare module "core" {
|
||||
}
|
||||
|
||||
type AuthSchema = Static<typeof authConfigSchema>;
|
||||
export type CreateUserPayload = { email: string; password: string; [key: string]: any };
|
||||
|
||||
export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
private _authenticator?: Authenticator;
|
||||
@@ -36,8 +37,12 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
return to;
|
||||
}
|
||||
|
||||
get enabled() {
|
||||
return this.config.enabled;
|
||||
}
|
||||
|
||||
override async build() {
|
||||
if (!this.config.enabled) {
|
||||
if (!this.enabled) {
|
||||
this.setBuilt();
|
||||
return;
|
||||
}
|
||||
@@ -84,14 +89,6 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
return this._controller;
|
||||
}
|
||||
|
||||
getMiddleware() {
|
||||
if (!this.config.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new AuthController(this).getMiddleware;
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
return authConfigSchema;
|
||||
}
|
||||
@@ -287,11 +284,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
async createUser({
|
||||
email,
|
||||
password,
|
||||
...additional
|
||||
}: { email: string; password: string; [key: string]: any }) {
|
||||
async createUser({ email, password, ...additional }: CreateUserPayload): Promise<DB["users"]> {
|
||||
const strategy = "password";
|
||||
const pw = this.authenticator.strategy(strategy) as PasswordStrategy;
|
||||
const strategy_value = await pw.hash(password);
|
||||
|
||||
@@ -1,42 +1,17 @@
|
||||
import type { AppAuth } from "auth";
|
||||
import { type ClassController, isDebug } from "core";
|
||||
import { Hono, type MiddlewareHandler } from "hono";
|
||||
import { Controller } from "modules/Controller";
|
||||
|
||||
export class AuthController implements ClassController {
|
||||
constructor(private auth: AppAuth) {}
|
||||
export class AuthController extends Controller {
|
||||
constructor(private auth: AppAuth) {
|
||||
super();
|
||||
}
|
||||
|
||||
get guard() {
|
||||
return this.auth.ctx.guard;
|
||||
}
|
||||
|
||||
getMiddleware: MiddlewareHandler = async (c, next) => {
|
||||
// @todo: ONLY HOTFIX
|
||||
// middlewares are added for all routes are registered. But we need to make sure that
|
||||
// only HTML/JSON routes are adding a cookie to the response. Config updates might
|
||||
// also use an extension "syntax", e.g. /api/system/patch/data/entities.posts
|
||||
// This middleware should be extracted and added by each Controller individually,
|
||||
// but it requires access to the auth secret.
|
||||
// Note: This doesn't mean endpoints aren't protected, just the cookie is not set.
|
||||
const url = new URL(c.req.url);
|
||||
const last = url.pathname.split("/")?.pop();
|
||||
const ext = last?.includes(".") ? last.split(".")?.pop() : undefined;
|
||||
if (
|
||||
!this.auth.authenticator.isJsonRequest(c) &&
|
||||
["GET", "HEAD", "OPTIONS"].includes(c.req.method) &&
|
||||
ext &&
|
||||
["js", "css", "png", "jpg", "jpeg", "svg", "ico"].includes(ext)
|
||||
) {
|
||||
isDebug() && console.log("Skipping auth", { ext }, url.pathname);
|
||||
} else {
|
||||
const user = await this.auth.authenticator.resolveAuthFromRequest(c);
|
||||
this.auth.ctx.guard.setUserContext(user);
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
|
||||
getController(): Hono<any> {
|
||||
const hono = new Hono();
|
||||
override getController() {
|
||||
const hono = this.create();
|
||||
const strategies = this.auth.authenticator.getStrategies();
|
||||
|
||||
for (const [name, strategy] of Object.entries(strategies)) {
|
||||
|
||||
38
app/src/auth/middlewares.ts
Normal file
38
app/src/auth/middlewares.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { Permission } from "core";
|
||||
import type { Context } from "hono";
|
||||
import { createMiddleware } from "hono/factory";
|
||||
import type { ServerEnv } from "modules/Module";
|
||||
|
||||
async function resolveAuth(app: ServerEnv["Variables"]["app"], c: Context<ServerEnv>) {
|
||||
const resolved = c.get("auth_resolved") ?? false;
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
if (!app.module.auth.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const authenticator = app.module.auth.authenticator;
|
||||
const guard = app.modules.ctx().guard;
|
||||
|
||||
guard.setUserContext(await authenticator.resolveAuthFromRequest(c));
|
||||
}
|
||||
|
||||
export const auth = createMiddleware<ServerEnv>(async (c, next) => {
|
||||
await resolveAuth(c.get("app"), c);
|
||||
await next();
|
||||
});
|
||||
|
||||
export const permission = (...permissions: Permission[]) =>
|
||||
createMiddleware<ServerEnv>(async (c, next) => {
|
||||
const app = c.get("app");
|
||||
await resolveAuth(app, c);
|
||||
|
||||
const p = Array.isArray(permissions) ? permissions : [permissions];
|
||||
const guard = app.modules.ctx().guard;
|
||||
for (const permission of p) {
|
||||
guard.throwUnlessGranted(permission);
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
Reference in New Issue
Block a user