Added auth and permission check middleware
This commit is contained in:
parent
3aaec5a323
commit
951115fcce
74
apps/backend/src/middlewares/authInfo.ts
Normal file
74
apps/backend/src/middlewares/authInfo.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import { createMiddleware } from "hono/factory";
|
||||
import HonoEnv from "../types/HonoEnv";
|
||||
import db from "../drizzle";
|
||||
import { users } from "../drizzle/schema/users";
|
||||
import { permissionsToUsers } from "../drizzle/schema/permissionsToUsers";
|
||||
import { rolesToUsers } from "../drizzle/schema/rolesToUsers";
|
||||
import { and, eq, isNull, or } from "drizzle-orm";
|
||||
import { rolesSchema } from "../drizzle/schema/roles";
|
||||
import { permissionsToRoles } from "../drizzle/schema/permissionsToRoles";
|
||||
import { permissionsSchema } from "../drizzle/schema/permissions";
|
||||
import { RoleCode } from "../data/roles";
|
||||
import { SpecificPermissionCode } from "../data/permissions";
|
||||
|
||||
const authInfo = createMiddleware<HonoEnv>(async (c, next) => {
|
||||
const { uid, currentUser } = c.var;
|
||||
|
||||
if (uid && !currentUser) {
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(
|
||||
and(
|
||||
eq(users.id, uid),
|
||||
eq(users.isEnabled, true),
|
||||
isNull(users.deletedAt)
|
||||
)
|
||||
)
|
||||
.leftJoin(
|
||||
permissionsToUsers,
|
||||
eq(permissionsToUsers.userId, users.id)
|
||||
)
|
||||
.leftJoin(rolesToUsers, eq(rolesToUsers.userId, users.id))
|
||||
.leftJoin(rolesSchema, eq(rolesToUsers.roleId, rolesSchema.id))
|
||||
.leftJoin(
|
||||
permissionsToRoles,
|
||||
eq(permissionsToRoles.roleId, rolesSchema.id)
|
||||
)
|
||||
.leftJoin(
|
||||
permissionsSchema,
|
||||
or(
|
||||
eq(permissionsSchema.id, permissionsToUsers.permissionId),
|
||||
eq(permissionsSchema.id, permissionsToRoles.permissionId)
|
||||
)
|
||||
);
|
||||
|
||||
const roles = new Set<RoleCode>();
|
||||
const permissions = new Set<SpecificPermissionCode>();
|
||||
|
||||
user.forEach((user) => {
|
||||
if (user.roles?.code) {
|
||||
roles.add(user.roles.code as RoleCode);
|
||||
}
|
||||
|
||||
if (user.permissions?.code) {
|
||||
permissions.add(
|
||||
user.permissions.code as SpecificPermissionCode
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
console.log("roles", Array.from(roles));
|
||||
console.log("permissions", Array.from(permissions));
|
||||
|
||||
c.set("currentUser", {
|
||||
name: user[0].users.name,
|
||||
permissions: Array.from(permissions),
|
||||
roles: Array.from(roles),
|
||||
});
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
export default authInfo;
|
||||
21
apps/backend/src/middlewares/checkPermission.ts
Normal file
21
apps/backend/src/middlewares/checkPermission.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { createMiddleware } from "hono/factory";
|
||||
import { PermissionCode } from "../data/permissions";
|
||||
import HonoEnv from "../types/HonoEnv";
|
||||
import { unauthorized } from "../errors/DashboardError";
|
||||
|
||||
const checkPermission = (...permissions: PermissionCode[]) =>
|
||||
createMiddleware<HonoEnv>(async (c, next) => {
|
||||
if (permissions.includes("*")) await next();
|
||||
else if (c.var.currentUser) {
|
||||
if (
|
||||
c.var.currentUser.permissions.some((p) =>
|
||||
permissions.includes(p)
|
||||
)
|
||||
)
|
||||
await next();
|
||||
} else {
|
||||
unauthorized();
|
||||
}
|
||||
});
|
||||
|
||||
export default checkPermission;
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
import { Hono } from "hono";
|
||||
import DashboardError from "../../errors/DashboardError";
|
||||
import authInfo from "../../middlewares/authInfo";
|
||||
import HonoEnv from "../../types/HonoEnv";
|
||||
|
||||
const devRoutes = new Hono().get("/error", async () => {
|
||||
throw new DashboardError({
|
||||
errorCode: "TEST_ERROR",
|
||||
message: "Test error",
|
||||
severity: "LOW",
|
||||
statusCode: 400,
|
||||
formErrors: {
|
||||
someField: "error",
|
||||
},
|
||||
const devRoutes = new Hono<HonoEnv>()
|
||||
.use(authInfo)
|
||||
.get("/middleware", async (c) => {
|
||||
return c.json({
|
||||
message: "Middleware works!",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export default devRoutes;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import { rolesToUsers } from "../../drizzle/schema/rolesToUsers";
|
|||
import { rolesSchema } from "../../drizzle/schema/roles";
|
||||
import HonoEnv from "../../types/HonoEnv";
|
||||
import requestValidator from "../../utils/requestValidator";
|
||||
import authInfo from "../../middlewares/authInfo";
|
||||
import checkPermission from "../../middlewares/checkPermission";
|
||||
|
||||
const userFormSchema = z.object({
|
||||
name: z.string().min(1).max(255),
|
||||
|
|
@ -41,19 +43,10 @@ const userUpdateSchema = userFormSchema.extend({
|
|||
});
|
||||
|
||||
const usersRoute = new Hono<HonoEnv>()
|
||||
.use(async (c, next) => {
|
||||
const uid = c.get("uid");
|
||||
|
||||
if (uid) {
|
||||
await next();
|
||||
} else {
|
||||
throw new HTTPException(401, {
|
||||
message: "Unauthorized",
|
||||
});
|
||||
}
|
||||
})
|
||||
.use(authInfo)
|
||||
.get(
|
||||
"/",
|
||||
checkPermission("users.readAll"),
|
||||
requestValidator(
|
||||
"query",
|
||||
z.object({
|
||||
|
|
@ -86,6 +79,7 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
//get user by id
|
||||
.get(
|
||||
"/:id",
|
||||
checkPermission("users.readAll"),
|
||||
requestValidator(
|
||||
"query",
|
||||
z.object({
|
||||
|
|
@ -144,7 +138,11 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
}
|
||||
)
|
||||
//create user
|
||||
.post("/", requestValidator("form", userFormSchema), async (c) => {
|
||||
.post(
|
||||
"/",
|
||||
checkPermission("users.create"),
|
||||
requestValidator("form", userFormSchema),
|
||||
async (c) => {
|
||||
const userData = c.req.valid("form");
|
||||
|
||||
const user = await db
|
||||
|
|
@ -178,10 +176,15 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
},
|
||||
201
|
||||
);
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
//update user
|
||||
.patch("/:id", requestValidator("form", userUpdateSchema), async (c) => {
|
||||
.patch(
|
||||
"/:id",
|
||||
checkPermission("users.update"),
|
||||
requestValidator("form", userUpdateSchema),
|
||||
async (c) => {
|
||||
const userId = c.req.param("id");
|
||||
const userData = c.req.valid("form");
|
||||
|
||||
|
|
@ -207,11 +210,13 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
return c.json({
|
||||
message: "User updated successfully",
|
||||
});
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
//delete user
|
||||
.delete(
|
||||
"/:id",
|
||||
checkPermission("users.delete"),
|
||||
requestValidator(
|
||||
"form",
|
||||
z.object({
|
||||
|
|
@ -263,7 +268,7 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
)
|
||||
|
||||
//undo delete
|
||||
.patch("/restore/:id", async (c) => {
|
||||
.patch("/restore/:id", checkPermission("users.restore"), async (c) => {
|
||||
const userId = c.req.param("id");
|
||||
|
||||
const user = (
|
||||
|
|
|
|||
8
apps/backend/src/types/HonoEnv.d.ts
vendored
8
apps/backend/src/types/HonoEnv.d.ts
vendored
|
|
@ -1,6 +1,14 @@
|
|||
import { SpecificPermissionCode } from "../data/permissions";
|
||||
import { RoleCode } from "../data/roles";
|
||||
|
||||
type HonoEnv = {
|
||||
Variables: {
|
||||
uid?: string;
|
||||
currentUser?: {
|
||||
name: string;
|
||||
permissions: SpecificPermissionCode[];
|
||||
roles: RoleCode[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user