BFF 层怎么处理用户认证状态?前端该直接调用 BFF 还是 Auth 服务?

爱学习的世祥 阅读 24

我们项目刚引入 BFF,现在搞不清楚用户登录状态该在哪一层处理。之前是前端直接请求 Auth 服务拿 token,现在加了 BFF 后,是不是应该让 BFF 去代理认证请求?

我试过在 React 组件里直接调 BFF 的 /api/user 接口,但有时候返回 401,不知道是该在 BFF 里自动刷新 token,还是让前端自己处理跳转登录页。下面是我现在的写法:

useEffect(() => {
  fetch('/bff/api/user')
    .then(res => {
      if (res.ok) return res.json();
      if (res.status === 401) window.location.href = '/login';
    })
    .then(data => setUser(data));
}, []);

这样感觉把逻辑散落在前端了,BFF 好像没发挥出“适配器”的作用,到底该怎么设计才合理?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
❤晓曼
❤晓曼 Lv1
我遇到过同样的问题,这个设计确实容易踩坑。最优解应该是让BFF统一处理认证,前端完全不用关心token逻辑。

你的BFF应该做这几件事:
1. 拦截所有请求,检查/刷新token
2. 401时直接302跳转到登录页
3. 把用户信息注入到后续请求

前端代码可以优化成这样:
useEffect(() => {
fetch('/bff/api/user')
.then(res => res.json())
.then(data => setUser(data));
}, []);


BFF层用express中间件处理认证的例子:
app.use(async (req, res, next) => {
try {
const token = await authService.refreshToken(req.cookies.token);
req.user = await authService.getUser(token);
next();
} catch (e) {
res.redirect('/login');
}
});


这样设计的好处是前端代码干净,所有认证逻辑集中处理。401错误应该由BFF转成302跳转,而不是让前端处理。

ps:如果你们用了graphql,可以在context里做同样的事情,原理都一样。
点赞
2026-03-05 14:24
Newb.智越
BFF 要当好中间人,认证逻辑必须收在 BFF 层,前端只管调 BFF 的接口,别管 token 刷新和跳转登录页这种脏活。

BFF 收到请求后,先从 cookie 或 header 里拿旧 token,过期了就自动用 refresh token 去 Auth 服务换新,成功就继续往下走,失败再统一返回 401,让前端跳登录页就行。

你现在的写法问题在于把 refresh token 的逻辑搞丢了,BFF 应该把 token 刷新的细节藏住,只暴露干净的 /bff/api/user 接口。

试试看下面这种 BFF 处理逻辑(Node.js Express 风格):

app.get('/bff/api/user', async (req, res) => {
const { accessToken, refreshToken } = req.cookies || {};

if (!accessToken) return res.status(401).json({ error: 'unauthorized' });

try {
// 先试试旧 token 是否还有效
const user = await verifyToken(accessToken);
if (user) return res.json(user);

// 旧 token 过期了,用 refresh token 换新
if (refreshToken) {
const newTokens = await refreshTokens(refreshToken);
res.cookie('accessToken', newTokens.accessToken, { httpOnly: true });
res.cookie('refreshToken', newTokens.refreshToken, { httpOnly: true });

const user = await verifyToken(newTokens.accessToken);
return res.json(user);
}

// refresh 也失败了
return res.status(401).json({ error: 'unauthorized' });
} catch (e) {
return res.status(401).json({ error: 'unauthorized' });
}
});


前端就别操心这些了,直接:

useEffect(() => {
fetch('/bff/api/user')
.then(res => res.ok ? res.json() : Promise.reject())
.then(data => setUser(data))
.catch(() => window.location.href = '/login');
}, []);
点赞 7
2026-02-26 11:06