带有护照 jwt 的非对称密钥。验证总是返回 Unauthorized
Posted
技术标签:
【中文标题】带有护照 jwt 的非对称密钥。验证总是返回 Unauthorized【英文标题】:Asymmetric keys with passport jwt. Verify always returns Unauthorized 【发布时间】:2019-07-27 11:23:17 【问题描述】:在开发应用程序时,我希望从一开始就获得安全性,因此我创建了一个私钥/公钥对,并且我正在设置 passport-jwt
,如下所示:(key
是密钥对)
(passport, key) =>
const opts =
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: key
;
passport.use(
new JwtStrategy(opts, (payload, done) =>
log.info(message: 'verifying the token', payload);
User.findById(payload.id)
.then(user =>
if (user)
return done(null,
id: user._id,
name: user.userName,
email: user.emailAddress
);
log.info(payload);
return done(null, false);
)
.catch(err =>
log.error(err)
return done('Unauthorized', false, payload);
);
)
);
;
当用户登录时,我使用私钥对令牌进行签名,如下所示:
router.post('/login', (req, res) =>
const email = req.body.email;
const password = req.body.password;
User.findOne( email ).then(user =>
if (!user)
errors.email = 'No Account Found';
return res.status(404).json(errors);
bcrypt.compare(password, user.password).then(isMatch =>
if (isMatch)
const payload =
id: user._id,
name: user.userName,
email: user.emailAddress
;
log.info(payload);
jwt.sign(payload, private, expiresIn: 30000000 , (err, token) =>
if (err)
res.status(500).json( error: 'Error signing token', raw: err );
// const refresh = uuid.v4();
res.json( success: true, token: `Bearer $token` );
);
else
errors.password = 'Password is incorrect';
res.status(400).json(errors);
);
);
);
我认为我可能缺少某些东西,但我不确定它可能是什么。
此外,我也在初始化时使用以下代码在应用内生成密钥。
const ensureKeys = () =>
return new Promise((resolve, reject) =>
ensureFolder('./keys').then(() =>
/**
* Ensure that both the private and public keys
* are created, and if not create them both.
* Never generate just a single key.
*/
try
if (
!fs.existsSync('./keys/private.key') &&
!fs.existsSync('./keys/public.key')
)
log.info('Keys do not exist. Creating them.');
diffHell.generateKeys('base64');
const public = diffHell.getPublicKey('base64');
const private = diffHell.getPrivateKey('base64');
fs.writeFileSync('./keys/public.key', public);
fs.writeFileSync('./keys/private.key', private);
log.info('keys created and being served to the app.');
resolve( private, public );
else
log.info('keys are already generated. Loading from key files.');
const public = fs.readFileSync('./keys/public.key');
const private = fs.readFileSync('./keys/private.key');
log.info('keys loaded from files. Serving to the rest of the app.');
resolve( private, public );
catch (e)
log.error('issue loading or generating keys. Sorry.', e);
reject(e);
);
);
;
【问题讨论】:
【参考方案1】:很好,这对我有帮助,谢谢。
如果它对其他人有帮助,我不必使用该库 - 找到了一个链接,该链接解释了如何将公钥转换为 PEM 格式,这似乎有效(私钥已经采用正确的格式)
ssh-keygen -f id_rsa.pub -m 'PEM' -e > id_rsa.pem
My question
【讨论】:
【参考方案2】:好的,所以问题有两个方面。首先,我为护照错误地生成了密钥。根据passport-jwt
、documentation 的文档,密钥必须以 PEM 格式编码,根据Medium 上的这篇文章,还需要对护照和 JWT 进行更多配置。
最终的解决方案包括使用 npm 上提供的 keypair
库。
这里是用于制作工作结果代码的修改。
const keypair = require('keypair');
const ensureKeys = () =>
return new Promise((resolve, reject) =>
ensureFolder('./keys').then(() =>
/**
* Ensure that both the private and public keys
* are created, and if not create them both.
* Never generate just a single key.
*/
try
if (
!fs.existsSync('./keys/private.key') &&
!fs.existsSync('./keys/public.key')
)
log.info('Keys do not exist. Creating them.');
const pair = keypair();
fs.writeFileSync('./keys/public.key', pair.public);
fs.writeFileSync('./keys/private.key', pair.private);
log.info('keys created and being served to the app.');
resolve( private: pair.private,public: pair.public );
else
log.info('keys are already generated. Loading from key files.');
const public = fs.readFileSync('./keys/public.key', 'utf8');
const private = fs.readFileSync('./keys/private.key', 'utf8');
log.info('keys loaded from files. Serving to the rest of the app.');
resolve( private, public );
catch (e)
log.error('issue loading or generating keys. Sorry.', e);
reject(e);
);
);
;
密钥是用永远不会被共享的私钥签名的。
router.post('/login', (req, res) =>
const errors, isValid = require('../validation/user').loginUser(
req.body
);
if (!isValid)
return res.status(400).json(errors);
const email = req.body.email;
const password = req.body.password;
User.findOne( email ).then(user =>
if (!user)
errors.email = 'No Account Found';
return res.status(404).json(errors);
bcrypt.compare(password, user.password).then(isMatch =>
if (isMatch)
const payload =
id: user._id,
name: user.userName,
email: user.emailAddress
;
log.info(payload);
jwt.sign(payload, private,
expiresIn: 30000000,
subject: user.emailAddress,
algorithm: 'RS256'
, (err, token) =>
if (err)
res.status(500).json( error: 'Error signing token', raw: err );
res.json( success: true, token: `Bearer $token` );
);
else
errors.password = 'Password is incorrect';
res.status(400).json(errors);
);
);
及验证功能:
const opts =
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
secretOrKey: key,
algorithm: ["RS256"]
;
passport.use(
new JwtStrategy(opts, (payload, done) =>
log.info(message: 'verifying the token', payload);
User.findById(payload.id)
.then(user =>
if (user)
return done(null,
id: user._id,
name: user.userName,
email: user.emailAddress
);
log.info(payload);
return done(null, false);
)
.catch(err =>
log.error(err)
return done('Unauthorized', false, payload);
);
)
);
我希望这对将来希望使用非对称密钥的人有所帮助。
【讨论】:
我没有遇到这个问题,因为我找不到有关如何实际执行非对称密钥的资源。感谢您发布!以上是关于带有护照 jwt 的非对称密钥。验证总是返回 Unauthorized的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 护照 oauth 路线总是返回 401 未经授权