NodeJS 基于角色的身份验证系统fastify

jyztefdp  于 2023-10-17  发布在  Node.js
关注(0)|答案(3)|浏览(158)

我目前正在做一个fastify项目,在那里我使用fastify-jwt为我的用户创建Bearer令牌。
在我访问它的路线如下:

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

所以知道我想一些路线无法访问的“正常”用户,只有“管理员”用户。通常,这些信息都在令牌中。我可以大访问只有管理员内的功能,由我想直接不给予访问的路线。所以直接叫“不准”。
我发现fastify警卫,但它不工作.

ou6hu8tu

ou6hu8tu1#

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

//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函数,并在您想要的路由中使用它(首先包括它)。

mpgws1up

mpgws1up2#

你可以使用firebase认证或任何,并把用户在一个数据库与模式具有属性“角色”,然后检查这个角色在中间件,例如,如果角色==0其管理员等。

tpxzln5u

tpxzln5u3#

我只是从事实现工作,我想在这里留下我的方法,以防其他人可能会发现它有用。
Fastify有很好的插件来实现身份验证和授权。授权是验证你是谁,你说你是谁,授权是验证你有权访问资源,这取决于你是谁。
我发现最具可扩展性和维护性的方法是使用插件。我使用的插件是:

  1. https://www.npmjs.com/package/@fastify/auth
  2. https://www.npmjs.com/package/@fastify/jwt
    对于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攻击。授权可以在稍后完成,如在precedent步骤中。角色的值将传递到路由的options.config中,您需要像上面的示例那样检查授权。
对于为授权和身份验证添加的装饰器,您可能需要扩展Fastify类型。你可以这样做:

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

此示例是通用的,涵盖了对选定路由的授权和身份验证检查。

相关问题