基于角色的身份验证系统快速

发布于 2025-01-20 10:51:03 字数 344 浏览 4 评论 0原文

我目前正在从事一个快速项目,在该项目中,我使用fastify-jwt为用户创建了持票人令牌。

在路线中,我可以通过以下方式进行操作:

fastify.get(
    "/test",
    {
        preValidation: [fastify.authenticate],
    },
    Collection.functionX
);

因此,只需“正常”用户无法访问某些路线,仅适用于“ admin”用户。通常,此信息在令牌内。我可以通过直接访问该路线访问该功能中的管理员。因此,它直接称为“不允许”。

我找到了Fastify Guard,但它不起作用。

I'm currently working on a fastify project, where I use fastify-jwt to create Bearer tokens to my users.

And in the routes I acces it with following:

fastify.get(
    "/test",
    {
        preValidation: [fastify.authenticate],
    },
    Collection.functionX
);

So know I want some routes not accessible for "normal" users, only for "admin" users. Normally this information is within the token. I can grand access to only admins within the function, by I want to directly not give access to the route. So it directly calls "not allowed".

I found fastify Guard but it is not working.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

怀里藏娇 2025-01-27 10:51:03

我刚刚在实施中工作,我想在这里离开我的方法,以防其他人觉得这很有用。

Fastify具有出色的插件可以实现,身份验证和授权。授权是验证您是您说的是谁,并且授权是您可以根据自己的身份来访问资源的验证。

我发现最可扩展和可维护的方法是使用插件。我使用的插件是:

  1. https://wwwww.npmjs.coms.coms.com/package/ppackage/ppackage/@astfastify/ auth
  2. https://www.npmjs.coms.com/package/ppackage/ppackage/ppackage/ppackage/ppackage/ppackage/@fastify/jwtify/jwtify/jwwt

对于使用JWT进行身份验证,您可以创建一个这样的插件:

import fastifyPlugin from 'fastify-plugin';
import fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt';
import { FastifyRequest, FastifyReply } from 'fastify';

export default fastifyPlugin<FastifyJWTOptions>(async (fastify) => {
    fastify.register(fastifyJwt, {
        secret: '',
        decode: { complete: true },
        sign: { algorithm: 'RS256', expiresIn: '1h' },
        decoratorName: 'jwtUser',
    });

    fastify.decorate(
        'authenticate',
        async (request: FastifyRequest, reply: FastifyReply) => {
            try {
                await request.jwtVerify();
            } catch (error) {
                throw fastify.httpErrors.unauthorized();
            }
        }
    );
});

然后,对于授权,您将创建一个这样的插件:

import fastifyPlugin from 'fastify-plugin';
import auth, { FastifyAuthPluginOptions } from '@fastify/auth';
import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify';

export default fastifyPlugin<FastifyAuthPluginOptions>(
    async (fastify: FastifyInstance) => {
        fastify.register(auth);

        fastify.decorate(
            'authorize',
            async (request: FastifyRequest, reply: FastifyReply) => {

                const allowedRoles = request.routeOptions.config.allowedRoles;

                if (allowedRoles && request.jwtUser.payload.user) {
                    const userRoles = request.jwtUser.payload.user
                        ? request.jwtUser.payload.user.roles
                        : [];

                    if (!allowedRoles.some((role: any) => userRoles.includes(role))) {
                        throw fastify.httpErrors.unauthorized();
                    }
                }
            }
        );
    }
);

您会从需要它们的路线中调用它们:

import { FastifyPluginAsync } from 'fastify';

const root: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
    fastify.get(
        '/',
        {
            schema: {},
            onRequest: [fastify.authenticate],
            config: { allowedRoles: ['admin'] },
            preHandler: fastify.auth([fastify.authorize]),
        },
        (request, reply) => {
            return reply.code(200).send('Welcome!')
        }
    );
};

export default root;

从fastify文档中,身份验证更好在生命周期较早进行以防止DOS攻击。授权可以在稍后进行,就像在汉将步骤中一样。角色的值将通过options.config传递。路由您需要像上面示例一样检查的授权。

对于添加授权和身份验证的装饰器,您可能需要扩展快速类型。您可以这样做:

import 'fastify';
import { FastifyRequest, FastifyReply } from 'fastify';
declare module 'fastify' {

    /**
     * Type function to extend FastifyInstance to work with hook authentication
     * onRequest: [fastify.authenticate] defined at src\plugins\jwtVerification.ts
     */
    type Authenticate = (
        request: FastifyRequest,
        reply: FastifyReply
    ) => Promise<void>;

    /**
     * Type function to extend FastifyInstance to work with hook authentorization
     * preHandler: fastify.auth([fastify.authorize]) defined at src\plugins\roleBasedAutorization.ts
     */
    type Authorize = (
        request: FastifyRequest,
        reply: FastifyReply
    ) => Promise<void>;

    /** Apply the extension */
    interface FastifyInstance {
        authenticate: Authenticate;
        authorize: Authorize;
    }

    /**
     * Interface to extend FastifyContextConfig, so the allowedRoles property can be added to
     * the options.config object in routes using authorization
     */
    interface FastifyContextConfig {
        allowedRoles?: string[];
    }
}

此示例是一般的,并且涵盖了所选路由的授权和身份验证检查。

I just worked implementing, and I would like to leave my approach here in case someone else might find it useful.

Fastify has great plugins to achieve both, authentication and authorization. Authorization is to verify you are who you say you are, and authorization is validation that you have access to a resource depending on who you are.

I found the most scalable and maintainable approach is to use plugins. The plugins I used are:

  1. https://www.npmjs.com/package/@fastify/auth
  2. https://www.npmjs.com/package/@fastify/jwt

For authentication with JWT you can create a plugin like this:

import fastifyPlugin from 'fastify-plugin';
import fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt';
import { FastifyRequest, FastifyReply } from 'fastify';

export default fastifyPlugin<FastifyJWTOptions>(async (fastify) => {
    fastify.register(fastifyJwt, {
        secret: '',
        decode: { complete: true },
        sign: { algorithm: 'RS256', expiresIn: '1h' },
        decoratorName: 'jwtUser',
    });

    fastify.decorate(
        'authenticate',
        async (request: FastifyRequest, reply: FastifyReply) => {
            try {
                await request.jwtVerify();
            } catch (error) {
                throw fastify.httpErrors.unauthorized();
            }
        }
    );
});

Then, for authorization you would create another plugin like this:

import fastifyPlugin from 'fastify-plugin';
import auth, { FastifyAuthPluginOptions } from '@fastify/auth';
import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify';

export default fastifyPlugin<FastifyAuthPluginOptions>(
    async (fastify: FastifyInstance) => {
        fastify.register(auth);

        fastify.decorate(
            'authorize',
            async (request: FastifyRequest, reply: FastifyReply) => {

                const allowedRoles = request.routeOptions.config.allowedRoles;

                if (allowedRoles && request.jwtUser.payload.user) {
                    const userRoles = request.jwtUser.payload.user
                        ? request.jwtUser.payload.user.roles
                        : [];

                    if (!allowedRoles.some((role: any) => userRoles.includes(role))) {
                        throw fastify.httpErrors.unauthorized();
                    }
                }
            }
        );
    }
);

And you would call them from the routes you need them like this:

import { FastifyPluginAsync } from 'fastify';

const root: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
    fastify.get(
        '/',
        {
            schema: {},
            onRequest: [fastify.authenticate],
            config: { allowedRoles: ['admin'] },
            preHandler: fastify.auth([fastify.authorize]),
        },
        (request, reply) => {
            return reply.code(200).send('Welcome!')
        }
    );
};

export default root;

From the Fastify docs, authentication is better done earlier on the lifecycle to prevent DOS attacks. Authorization can be done later on like in the preHandler step. The values of the roles would be passed on the options.config of the route where you need the authorization checked like in the example above.

For the decorators added for authorization and for authentication you might need to extend Fastify types. You can do it like this:

import 'fastify';
import { FastifyRequest, FastifyReply } from 'fastify';
declare module 'fastify' {

    /**
     * Type function to extend FastifyInstance to work with hook authentication
     * onRequest: [fastify.authenticate] defined at src\plugins\jwtVerification.ts
     */
    type Authenticate = (
        request: FastifyRequest,
        reply: FastifyReply
    ) => Promise<void>;

    /**
     * Type function to extend FastifyInstance to work with hook authentorization
     * preHandler: fastify.auth([fastify.authorize]) defined at src\plugins\roleBasedAutorization.ts
     */
    type Authorize = (
        request: FastifyRequest,
        reply: FastifyReply
    ) => Promise<void>;

    /** Apply the extension */
    interface FastifyInstance {
        authenticate: Authenticate;
        authorize: Authorize;
    }

    /**
     * Interface to extend FastifyContextConfig, so the allowedRoles property can be added to
     * the options.config object in routes using authorization
     */
    interface FastifyContextConfig {
        allowedRoles?: string[];
    }
}

This example is general, and covers both authorization and authentication checks on selected routes.

空袭的梦i 2025-01-27 10:51:03

我知道这个问题已经存在很长时间了。但我将把我的解决方案留在这里:

//import { FastifyRequest, FastifyReply } from 'fastify';
//import { findOneUser } from '../services/userService';

const checkRole = (roles: string[]) => async (
    request: FastifyRequest,
    reply: FastifyReply,
    next: () => void
): Promise<void> => {

    const userId = request.user.id;
    const user = await findOneUser({ id: userId });

    if (!user)
        return reply.status(401)
            .send({ success: false, error: 'Unauthorized' });

    const roleExists = roles.some(role => role === user['role']);

    if (!roleExists) 
        return reply.status(401)
            .send({ success: false, error: 'Unauthorized' });
    
    return next();
};

导入 checkRole 函数并在您想要的路由中使用它(将其包含在 preHandler 中)。

I know the question has been around for a long time. But I'll leave my solution here:

//import { FastifyRequest, FastifyReply } from 'fastify';
//import { findOneUser } from '../services/userService';

const checkRole = (roles: string[]) => async (
    request: FastifyRequest,
    reply: FastifyReply,
    next: () => void
): Promise<void> => {

    const userId = request.user.id;
    const user = await findOneUser({ id: userId });

    if (!user)
        return reply.status(401)
            .send({ success: false, error: 'Unauthorized' });

    const roleExists = roles.some(role => role === user['role']);

    if (!roleExists) 
        return reply.status(401)
            .send({ success: false, error: 'Unauthorized' });
    
    return next();
};

Import the checkRole function and use it in the route you want (include this in preHandler).

世态炎凉 2025-01-27 10:51:03

您可以使用firebase身份验证或任何身份验证,并将用户放入具有属性“角色”的架构的数据库中,然后在中间件中检查此角色,例如,如果角色== 0其管理员等等。

you can use firebase authentication or any ,and put the user in a data base with a schema has property "role",then check this role in middleware,for example if role==0 its admin and so on .

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文