Added auth and permission check middleware

This commit is contained in:
sianida26 2024-05-08 11:29:12 +07:00
parent 3aaec5a323
commit 951115fcce
6 changed files with 181 additions and 75 deletions

View 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;

View 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;

View File

@ -1,15 +1,13 @@
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!",
});
});

View File

@ -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 = (

View File

@ -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[];
};
};
};