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

如何基于配置实现按用户名限制期货资产访问的安全逻辑

实现方案

你现有代码的逻辑方向是对的,核心问题出在异步权限加载的时序错误、变量误用两个点上,createUserFuturesAssetsConstraints本身的结构不需要大改,按下面的步骤修正即可:

首先修复已知的逻辑错误

  • 你之前把权限存储对象userPermittedFutures和权限查询函数getPermittedFuturesAssets搞混了,在接口里判断的是函数上的属性,根本读不到用户权限
  • getPermittedFuturesAssets重试的时候没有传入traderId,导致权限查询始终失败
  • 全局获取当前用户的方式在并发请求场景下会出现用户串号的问题,应该直接从请求对象req.user里取当前登录用户

修正后的完整代码

1. 先改造权限查询函数为Promise异步形式,保证能等待权限加载完成

const userPermittedFutures = {};

// 改造为返回Promise的异步函数,支持等待权限加载完成
const getPermittedFuturesAssets = (traderId) => {
  return new Promise((resolve, reject) => {
    if (!pgClient) {
      setTimeout(() => {
        getPermittedFuturesAssets(traderId).then(resolve).catch(reject);
      }, 1000);
      return;
    }
    const query = {
      name: 'fetch-futures-assets-permissions',
      text: 'SELECT trader_id, pair, pair_limit ' +
          'FROM common.accounts_pairs_permits app ' +
          'WHERE exists(SELECT * FROM future.instrument ap WHERE ap.symbol = app.pair) AND trader_id = $1',
      values: [traderId],
    };
    pgClient.query(query, (err, res) => {
      if (err) {
        console.error("Can't get account permitted futures permits. Retrying in a second...");
        setTimeout(() => {
          getPermittedFuturesAssets(traderId).then(resolve).catch(reject);
        }, 1000);
        return;
      }
      // 把用户权限写入全局缓存
      for (let row of res.rows) {
        addUserFuturesConstraints(row.trader_id, row.pair, row.pair_limit);
      }
      resolve();
    });
  })
}

function addUserFuturesConstraints(trading_id, futuresAsset, limit) {
  if (!userPermittedFutures[trading_id]) {
    let user_permitted_limits = {}
    user_permitted_limits[futuresAsset] = createUserFuturesAssetsConstraints(limit);
    userPermittedFutures[trading_id] = user_permitted_limits;
  } else {
    userPermittedFutures[trading_id][futuresAsset] = createUserFuturesAssetsConstraints(limit);
  }
}

function createUserFuturesAssetsConstraints(pairQuantityLimit) {
  return {
    pairQuantityLimit: parseFloat(pairQuantityLimit),
    splitConstraints: [],
  }
}

2. 修正/futures接口的资产过滤逻辑

app.get('/futures', checkAuthenticated, async (req, res) => {
  try {
    // 先从请求对象取当前用户,避免并发串号
    const currentUser = req.user.username;
    const traderId = traderIdMnemonicMapping[currentUser];
    if (!traderId) {
      return res.status(403).send({
        status: 'fail',
        message: '未找到对应用户交易权限'
      });
    }

    // 先加载用户权限
    await getPermittedFuturesAssets(traderId);

    // 查询全量期货资产
    const query = {
      name: 'fetch-futures-portfolios',
      text: 'SELECT ' +
          'future.instrument.symbol ' +
          '....... ' +
          'WHERE future.exchange.name = $1',
      values: ['Futures'],
    };
    const futuresPortfolios = await pgClient.query(query);
    const allFutures = futuresPortfolios.rows.map(item => item.symbol);

    // 过滤用户有权限的资产
    const allowedAssets = userPermittedFutures[traderId] ? Object.keys(userPermittedFutures[traderId]) : [];
    // 取全量资产和用户权限的交集,避免返回数据库里不存在的资产
    const allowedFuturesAssetsForUser = allFutures.filter(asset => allowedAssets.includes(asset));

    res.status(200).send(allowedFuturesAssetsForUser);
  } catch (err) {
    console.log("接口处理失败: " + err.message);
    res.status(503).send({
      status: 'fail',
      message: err.message
    });
  }
});

3. 交易接口直接挂载现有校验中间件即可

所有需要限制资产访问的交易接口,直接加isUserAbleToTradeFutures中间件就行,现有逻辑不需要改:

// 示例:下单接口加权限校验
app.post('/futures/order', checkAuthenticated, isUserAbleToTradeFutures, async (req, res) => {
  // 你的下单逻辑
})

校验逻辑说明

  • 普通用户访问/futures接口时,只会返回数据库中存在、且该用户有权限的资产列表
  • 用户发起交易请求时,中间件会自动校验请求的资产是否在用户权限列表内,同时检查交易额度是否超过限制
  • 管理员用户不受上述规则限制,可访问所有资产

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:45:02