如何用Passport-JWT认证Hyperledger Composer REST API并限制注册用户访问
刚好之前帮朋友实现过类似的需求,用Passport-JWT把Hyperledger Composer的REST端点保护起来,用户数据存在MySQL里,只允许注册用户访问。给你梳理一下完整的实现步骤,都是亲测能跑通的:
1. 先搭好依赖环境
首先得安装需要的npm包,Passport-JWT、MySQL驱动、密码哈希工具这些都不能少:
npm install passport passport-jwt mysql2 bcryptjs dotenv
2. 配置MySQL用户存储
先在MySQL里创建用户表,密码一定要用哈希存储,绝对不能明文保存:
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, -- 存储bcrypt哈希后的密码 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
然后写个MySQL操作的工具文件db.js,用来查询用户信息:
const mysql = require('mysql2/promise'); require('dotenv').config(); // 创建数据库连接池,避免频繁创建销毁连接 const pool = mysql.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, connectionLimit: 10 }); // 根据用户名查询用户 async function getUserByUsername(username) { const [rows] = await pool.execute('SELECT * FROM users WHERE username = ?', [username]); return rows[0]; } module.exports = { getUserByUsername };
3. 配置Passport-JWT验证策略
接下来写Passport的JWT配置文件passport-config.js,定义JWT的提取方式、验证密钥,以及如何从MySQL验证用户:
const passport = require('passport'); const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; const { getUserByUsername } = require('./db'); require('dotenv').config(); const opts = { // 从请求头的Authorization字段提取Bearer Token jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // JWT的密钥,存在.env文件里保密,别硬编码 secretOrKey: process.env.JWT_SECRET }; passport.use(new JwtStrategy(opts, async (jwtPayload, done) => { try { // 根据JWT载荷里的用户名查询数据库 const user = await getUserByUsername(jwtPayload.username); if (user) { // 找到用户,验证通过 return done(null, user); } // 没找到用户,验证失败 return done(null, false); } catch (err) { return done(err, false); } })); module.exports = passport;
4. 给Composer REST Server添加自定义中间件
Composer REST Server支持添加自定义Express中间件,我们把Passport验证逻辑加进去,同时新增一个登录接口用来生成JWT。写个middleware.js:
const express = require('express'); const passport = require('./passport-config'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const { getUserByUsername } = require('./db'); const router = express.Router(); // 登录接口:用户提交用户名密码,验证成功后返回JWT router.post('/login', async (req, res) => { try { const { username, password } = req.body; const user = await getUserByUsername(username); if (!user) { return res.status(401).json({ message: '用户名或密码错误' }); } // 验证密码哈希是否匹配 const isPasswordMatch = await bcrypt.compare(password, user.password); if (!isPasswordMatch) { return res.status(401).json({ message: '用户名或密码错误' }); } // 生成JWT,有效期设为1小时(可根据需求调整) const token = jwt.sign( { username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' } ); res.json({ token: `Bearer ${token}` }); } catch (err) { res.status(500).json({ message: '服务器内部错误' }); } }); module.exports = function (app) { // 先挂载登录接口,这个接口不需要验证 app.use(router); // 初始化Passport app.use(passport.initialize()); // 把JWT验证中间件应用到所有/api开头的端点(Composer生成的REST接口默认是/api前缀) app.use('/api', passport.authenticate('jwt', { session: false })); };
5. 启动Composer REST Server并加载中间件
启动的时候用-m参数指定我们写的中间件文件:
composer-rest-server -c admin@your-network-name -n never -w true -m ./middleware.js
记得把admin@your-network-name替换成你自己的Composer网络卡片名称。
6. 测试验证流程
- 注册用户:可以写个简单的注册接口,或者手动在MySQL里插入用户数据,密码要用bcrypt哈希生成,比如:
const bcrypt = require('bcryptjs'); console.log(bcrypt.hashSync('your-password', 10)); // 把生成的哈希值插入数据库
- 获取JWT:调用
POST /login接口,提交用户名和密码,拿到返回的token。 - 访问受保护端点:访问Composer的REST接口(比如
GET /api/Asset),在请求头里加上Authorization: Bearer <你的token>,就能正常访问;如果不带token或者token无效,会返回401未授权。
一些注意事项
- 所有敏感配置(数据库信息、JWT密钥)都要放在
.env文件里,绝对不要硬编码到代码中。 - JWT的有效期根据业务需求调整,不要太长也不要太短。
- 如果只需要保护部分端点,可以修改中间件的路由匹配规则,比如只保护
/api/transactions而不是全部/api前缀的接口。
内容的提问来源于stack exchange,提问作者Honey Shah




