You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express中req.user在Elysia JS中的等价实现方案问询

在Elysia JS中实现类似Express req.user的请求级用户信息存储

核心思路

Elysia没有直接对应Express req.user的API,但可以通过请求上下文存储(ctx.store)或扩展上下文属性来实现请求生命周期内的用户信息共享,完全满足你的需求。


先回顾你的Express实现(示例)

const jwt = require('jsonwebtoken');

// JWT认证中间件
const authenticateJWT = (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (authHeader) {
    const token = authHeader.split(' ')[1];
    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
      if (err) return res.sendStatus(403);
      req.user = user; // 存入req.user供后续复用
      next();
    });
  } else {
    res.sendStatus(401);
  }
};

// 权限校验中间件
const requireAdmin = (req, res, next) => {
  if (req.user?.role === 'admin') next();
  else res.sendStatus(403);
};

Elysia 实现方案

方案1:使用内置ctx.store存储用户信息(推荐,无需额外配置)

ctx.store是Elysia内置的请求级临时存储,每个请求独立,专门用于在同一请求的钩子、路由之间共享数据,完美替代req.user。

结合Elysia官方JWT插件实现:

import { Elysia } from 'elysia';
import jwt from '@elysiajs/jwt';

const app = new Elysia();

// 注册官方JWT插件
app.use(jwt({
  secret: process.env.JWT_SECRET
}));

// 自定义认证钩子:解析JWT并存储用户信息到ctx.store.user
app.hook('beforeHandle', async (ctx) => {
  const authHeader = ctx.headers.authorization;

  if (!authHeader) {
    ctx.set.status = 401;
    return 'Unauthorized';
  }

  const token = authHeader.split(' ')[1];
  try {
    // 验证JWT并解析用户信息
    const user = await ctx.jwt.verify(token);
    // 存入请求级存储
    ctx.store.user = user;
  } catch (err) {
    ctx.set.status = 403;
    return 'Forbidden: Invalid token';
  }
});

// 权限校验钩子:复用存储的用户信息
app.hook('beforeHandle', (ctx) => {
  // 仅对需要admin权限的路由启用,可通过路由分组或插件控制
  const user = ctx.store.user;
  if (!user || user.role !== 'admin') {
    ctx.set.status = 403;
    return 'Forbidden: Admin required';
  }
});

// 示例路由:直接复用用户信息
app.get('/protected', (ctx) => {
  return {
    message: `Hello, ${ctx.store.user.username}`,
    userInfo: ctx.store.user
  };
});

app.listen(3000);

方案2:扩展上下文属性(TypeScript友好)

如果使用TypeScript,你可以直接扩展Elysia的上下文类型,添加ctx.user属性,获得更好的类型提示:

import { Elysia } from 'elysia';
import jwt from '@elysiajs/jwt';

// 扩展Elysia上下文类型
declare module 'elysia' {
  interface Context {
    user: {
      id: string;
      username: string;
      role: string;
    };
  }
}

const app = new Elysia();

app.use(jwt({ secret: process.env.JWT_SECRET }))
  .hook('beforeHandle', async (ctx) => {
    const authHeader = ctx.headers.authorization;
    if (!authHeader) {
      ctx.set.status = 401;
      return 'Unauthorized';
    }

    const token = authHeader.split(' ')[1];
    try {
      ctx.user = await ctx.jwt.verify(token); // 直接赋值给ctx.user
    } catch (err) {
      ctx.set.status = 403;
      return 'Forbidden: Invalid token';
    }
  })
  .get('/admin', (ctx) => {
    return { message: `Welcome admin ${ctx.user.username}` };
  });

app.listen(3000);

进阶:封装成可复用插件

按照Elysia的插件化设计,可以把认证和权限校验封装成独立插件,方便在多个路由或应用中复用:

// auth.plugin.js
import { Elysia } from 'elysia';
import jwt from '@elysiajs/jwt';

// 认证插件
export const authPlugin = new Elysia()
  .use(jwt({ secret: process.env.JWT_SECRET }))
  .hook('beforeHandle', async (ctx) => {
    const authHeader = ctx.headers.authorization;
    if (!authHeader) {
      ctx.set.status = 401;
      return 'Unauthorized';
    }

    const token = authHeader.split(' ')[1];
    try {
      ctx.store.user = await ctx.jwt.verify(token);
    } catch (err) {
      ctx.set.status = 403;
      return 'Forbidden: Invalid token';
    }
  });

// Admin权限守卫插件
export const adminGuard = new Elysia()
  .hook('beforeHandle', (ctx) => {
    const user = ctx.store.user;
    if (!user || user.role !== 'admin') {
      ctx.set.status = 403;
      return 'Forbidden: Admin required';
    }
  });

// 主应用使用
import { Elysia } from 'elysia';
import { authPlugin, adminGuard } from './auth.plugin';

const app = new Elysia()
  .use(authPlugin) // 全局启用认证
  .get('/protected', (ctx) => ({ user: ctx.store.user }))
  .use(adminGuard) // 对后续路由启用admin权限校验
  .get('/admin/dashboard', (ctx) => ({ message: 'Admin dashboard' }));

app.listen(3000);

关键说明

  1. ctx.store是请求隔离的,每个请求的store都是独立对象,不会出现跨请求数据污染。
  2. 官方@elysiajs/jwt插件比手动使用jsonwebtoken更贴合Elysia生态,支持异步验证和自动集成上下文。
  3. 钩子的执行顺序是按照注册顺序来的,确保认证钩子在权限校验钩子之前执行。

内容的提问来源于stack exchange,提问作者Shiraku Yanai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:45:09