在 Moleculer 中实现 JWT 认证主要通过中间件和服务钩子来完成。下面为你详细介绍实现步骤和示例代码:
1. 安装依赖
1
| npm install jsonwebtoken @types/jsonwebtoken
|
2. 创建 JWT 服务
负责生成和验证 Token:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| const jwt = require('jsonwebtoken');
module.exports = { name: 'jwt', settings: { secret: 'your-secret-key', expiresIn: '1d' }, methods: { generateToken(payload) { return jwt.sign(payload, this.settings.secret, { expiresIn: this.settings.expiresIn }); }, verifyToken(token) { return new Promise((resolve, reject) => { jwt.verify(token, this.settings.secret, (err, decoded) => { if (err) return reject(err); resolve(decoded); }); }); } }, actions: { generate: { params: { payload: 'object' }, handler(ctx) { return this.generateToken(ctx.params.payload); } }, verify: { params: { token: 'string' }, handler(ctx) { return this.verifyToken(ctx.params.token); } } } };
|
3. 创建认证中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| module.exports = function AuthMiddleware(broker) { return { localAction: async function (handler, ctx) { if (ctx.action.auth === false) { return handler(ctx); } const token = ctx.meta.token || (ctx.meta.headers && ctx.meta.headers.authorization)?.replace('Bearer ', ''); if (!token) { throw new Error('Missing authentication token'); } try { const decoded = await ctx.call('jwt.verify', { token }); ctx.meta.user = decoded; return handler(ctx); } catch (err) { throw new Error('Invalid authentication token'); } } }; };
|
4. 注册中间件
在主服务中注册中间件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const { ServiceBroker } = require('moleculer'); const AuthMiddleware = require('./middleware/auth.middleware');
const broker = new ServiceBroker({ middlewares: [ AuthMiddleware ] });
broker.loadServices('./services');
broker.start();
|
5. 在服务中使用认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| module.exports = { name: 'users', actions: { login: { auth: false, params: { email: 'string', password: 'string' }, async handler(ctx) { const user = await this.verifyUser(ctx.params.email, ctx.params.password); const token = await ctx.call('jwt.generate', { payload: { userId: user.id, role: user.role } }); return { token, user }; } }, profile: { handler(ctx) { const user = ctx.meta.user; return this.getUserProfile(user.userId); } } } };
|
6. API 网关集成
如果使用 Moleculer API 网关,需要从 HTTP 请求中提取 Token:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const ApiGateway = require('moleculer-web');
module.exports = { name: 'api', mixins: [ApiGateway], settings: { routes: [ { path: '/api', aliases: { 'POST /login': 'users.login', 'GET /profile': 'users.profile' }, onBeforeCall(ctx, route, req, res) { const token = req.headers['authorization']?.replace('Bearer ', ''); if (token) { ctx.meta.token = token; } } } ] } };
|
7. 高级功能
(1)权限控制
在中间件中添加角色验证:
1 2 3 4
| if (ctx.action.role === 'admin' && ctx.meta.user.role !== 'admin') { throw new Error('Permission denied'); }
|
(2)Token 刷新机制
创建刷新 Token 的服务和接口,避免频繁登录。
(3)Token 黑名单
对于登出操作,将 Token 添加到 Redis 黑名单中。
总结
通过以上步骤,你可以在 Moleculer 中实现完整的 JWT 认证系统:
- JWT 服务负责生成和验证 Token
- 中间件全局拦截请求并验证 Token
- 通过
ctx.meta.user 在服务间传递用户信息
- API 网关负责从 HTTP 请求提取 Token
这种设计保持了服务间的解耦,同时确保认证逻辑的统一。