moleculer认证

在 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
// services/jwt.service.js
const jwt = require('jsonwebtoken');

module.exports = {
name: 'jwt',
settings: {
secret: 'your-secret-key', // 生产环境建议从环境变量获取
expiresIn: '1d'
},
methods: {
// 生成 Token
generateToken(payload) {
return jwt.sign(payload, this.settings.secret, {
expiresIn: this.settings.expiresIn
});
},

// 验证 Token
verifyToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(token, this.settings.secret, (err, decoded) => {
if (err) return reject(err);
resolve(decoded);
});
});
}
},
actions: {
// 对外暴露生成 Token 的接口
generate: {
params: {
payload: 'object'
},
handler(ctx) {
return this.generateToken(ctx.params.payload);
}
},

// 对外暴露验证 Token 的接口
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
// middleware/auth.middleware.js
module.exports = function AuthMiddleware(broker) {
return {
// 全局请求钩子
localAction: async function (handler, ctx) {
// 跳过不需要认证的 action
if (ctx.action.auth === false) {
return handler(ctx);
}

// 从请求头获取 Token
const token = ctx.meta.token ||
(ctx.meta.headers && ctx.meta.headers.authorization)?.replace('Bearer ', '');

if (!token) {
throw new Error('Missing authentication token');
}

try {
// 调用 JWT 服务验证 Token
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
// index.js
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
// services/users.service.js
module.exports = {
name: 'users',
actions: {
// 公开接口,无需认证
login: {
auth: false, // 跳过认证
params: {
email: 'string',
password: 'string'
},
async handler(ctx) {
// 验证用户 credentials
const user = await this.verifyUser(ctx.params.email, ctx.params.password);

// 生成 Token
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
// services/api-gateway.service.js
const ApiGateway = require('moleculer-web');

module.exports = {
name: 'api',
mixins: [ApiGateway],
settings: {
routes: [
{
path: '/api',
aliases: {
'POST /login': 'users.login',
'GET /profile': 'users.profile'
},
// 从请求头提取 Token 并注入上下文
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 认证系统:

  1. JWT 服务负责生成和验证 Token
  2. 中间件全局拦截请求并验证 Token
  3. 通过 ctx.meta.user 在服务间传递用户信息
  4. API 网关负责从 HTTP 请求提取 Token

这种设计保持了服务间的解耦,同时确保认证逻辑的统一。