我爱JWT.合作真的很有趣.我的问题是:如果我得到JWT并且我可以解码有效载荷,那么它是如何安全的?我不能只是从标题中获取令牌,解码并更改有效负载中的用户信息,并使用相同的正确编码密码将其发回?
我知道他们必须是安全的,但我真的很想了解这些技术.我错过了什么?谢谢!
使用数据库会话令牌系统,我可以使用用户名/密码进行用户登录,服务器可以生成令牌(例如uuid)并将其存储在数据库中并将该令牌返回给客户端.来自其上的每个请求都将包括令牌,并且服务器将查询令牌是否有效以及它属于哪个用户.
使用JWT,由于保留在服务器上的密钥和客户端保留并随每个请求发送的签名令牌的组合,因此无需为会话/令牌保存任何数据库.
这很好,但除了保存数据库检查每个请求(因为它只是检查哈希表,这将是快速的),我不清楚使用JWT的优点是什么.你能熟悉这个解释吗?让我们忽略cookie,它特别是如上所述的数据库自定义令牌和JWT,我试图比较和理解它的好处.
我开始学习 Nodejs,但我被困在了中间。我从 npm 安装了一个新库,它是express-jwt,运行后显示某种错误。附上错误的代码和日志,请大家帮帮忙!
const jwt = require('jsonwebtoken');
require('dotenv').config()
const expressJwt = require('express-jwt');
const User = require('../models/user');
exports.requireSignin = expressJwt({ secret: process.env.JWT_SECRET});
Run Code Online (Sandbox Code Playgroud)
下面是错误的日志。
[nodemon] starting `node app.js`
D:\shubh\proj\Nodejs\nodeapi\node_modules\express-jwt\lib\index.js:22
if (!options.algorithms) throw new Error('algorithms should be set');
^
**Error: algorithms should be set**
at module.exports (D:\shubh\proj\Nodejs\nodeapi\node_modules\express-jwt\lib\index.js:22:34)
at Object.<anonymous> (D:\shubh\proj\Nodejs\nodeapi\controllers\auth.js:64:26)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
Run Code Online (Sandbox Code Playgroud) 我使用express-jwt并通过jQuery创建我的令牌并将其保存在我的localStorage中:
$.ajax({
url: "http://localhost:8080/login",
type: 'POST',
data: formData,
error : function(err) {
console.log('Error!', err)
},
success: function(data) {
console.log('Success!')
localStorage.setItem('token', data.id_token);
}
});
Run Code Online (Sandbox Code Playgroud)
我的后端有一条受保护的路线,如:
app.get('/upload',jwt({secret: config.secret}), function(req, res) {
res.sendFile(path.join(__dirname + '/upload.html'));
});
Run Code Online (Sandbox Code Playgroud)
如何使用请求标头从localStorage发送令牌?
我有一种感觉,这将是一个快速的答案,但我似乎无法在网上找到任何明确的答案 - jsonwebtoken npm包和express-jwt npm包之间的区别是什么?我认为 express-jwt是在jsonwebtoken之上编写的,只是验证传入的令牌并设置req.user为JWT上的用户有效负载.
那是对的吗?很抱歉,如果这是一个总的noob问题...我刚刚开始学习身份验证和node/express,所以这对我来说都是新手.
我一直在我的服务器上使用Passport进行用户身份验证.当用户登录本地(使用用户名和密码),服务器就给他们一个JWT存储在本地存储,并且被发送回服务器,每个API调用需要用户身份验证.
现在我也想支持Facebook和Google登录.自从我开始使用Passport后,我认为最好继续使用Passport策略,使用passport-facebook和passport-google-oauth.
我将参考Facebook,但两种策略的行为都相同.它们都需要重定向到服务器路由('/ auth/facebook'和'/ auth/facebook/callback').该过程是成功的,以保存用户,包括他们的Facebook \谷歌ID和令牌上的令牌.
在服务器上创建用户时,会创建一个JWT(不依赖于从facebook\google收到的令牌).
... // Passport facebook startegy
var newUser = new User();
newUser.facebook = {};
newUser.facebook.id = profile.id;
newUser.facebook.token = token; // token received from facebook
newUser.facebook.name = profile.displayName;
newUser.save(function(err) {
if (err)
throw err;
// if successful, return the new user
newUser.jwtoken = newUser.generateJwt(); // JWT CREATION!
return done(null, newUser);
});
Run Code Online (Sandbox Code Playgroud)
问题是,在创建之后,我找不到将JWT发送到客户端的正确方法,因为我还应该重定向到我的应用程序.
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
session: false,
successRedirect …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种方法来使用Passport.js的Twitter策略,而无需在数据库中使用会话集合/表.这样做的原因是我们将会话集合中的所有数据保存得非常大,并且每当用户发出请求时我们都会保存数据库往返,因为我们不必每次都去数据库获取会话数据.
无论如何,我们应该能够使用令牌(JSON Web令牌)来验证用户,这篇伟大的文章如何描述:
https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
但我很困惑为什么没有一种简单的方法可以用Passport做到这一点?(文章在没有Passport的情况下完成所有工作 - 但是Passport肯定会覆盖这个吗?).
也许我正在过度思考这个问题并且这样做的方法就是省略我在Express中使用数据库会话的调用,然后Passport已经足够智能来处理JWT了?不知怎的,我怀疑.
例如,仅仅在我的Express服务器中注释掉这些代码是不够的:
//app.use(expressSession({
// secret: 'arrete_x_paulette',
// store: new MongoStore({mongooseConnection: mongoose.connection}),
// saveUninitialized: true,
// resave: true,
// cookie: {
// secure: false,
// maxage: 6000000
// },
// proxy: false
//}));
Run Code Online (Sandbox Code Playgroud)
和
//app.use(passport.session());
Run Code Online (Sandbox Code Playgroud)
那么使用Passport就足够了?
为什么有人会使用存储在数据库中的会话而不是使用基于JWT的身份验证?
目前我正在尝试收集有关如何实现身份验证系统(登录)的知识。在我的研究期间,我尝试在我的后端实施基于 JWT 的解决方案。
我有一个快速服务器,它允许我注册一个用户,存储它的密码(加密)和它的电子邮件。
在登录之后,它会生成一个访问令牌(短期,5 分钟),以访问受保护的路由,以及一个刷新令牌(长期,7 天),以便在前一个过期后生成新的访问令牌。
在我当前的实现中,我将刷新令牌存储在我的数据库中,因此每次我想生成新的访问令牌时都可以使用它。
但这安全吗?据我了解,在我的数据库中存储访问令牌是危险的,因此最好创建一个短期存在的 cookie 存储。但是……刷新令牌?据我所知,这会很危险,因为它基本上允许生成新的访问令牌,所以我不明白为什么不简单地在我的数据库中存储一个长期存在的访问令牌,在每次登录时生成一个新的。
什么是刷新令牌呢?
由于我遵循了一些教程来实现这一点,这就是我的 refresh_token 路由的外观
//get a new access token with a refresh token
app.post('/refresh_token', (req, res) => {
const token = req.cookies.refreshtoken
//if no token in request
if(!token) return res.send({accesstoken : ''});
//if we have a token we verify it
let payload = null;
try{
payload = verify(token, process.env.REFRESH_TOKEN_SECRET);
}catch(err){
return res.send({accesstoken: ''});
}
//if token is valid check if user exist
const user = fakeDB.find(user => user.id === …Run Code Online (Sandbox Code Playgroud) 在express-jwt文档中,提到了能够使用getToken函数从请求中获取令牌.
你如何在路线中使用这个电话?
app.use(jwt({
secret: 'hello world !',
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
}));
Run Code Online (Sandbox Code Playgroud) 当与Passport.js,Express和Mongoose一起使用时,我在NodeJS中遇到这个奇怪的问题。基本上,即使我发送的标题不止一个,我也会收到一条错误消息:“在将标题发送到客户端后无法设置标题”。
我读过其他文章,也尝试过,但没有一个起作用。
我已经解决了github问题,但似乎找不到解决方案。我遇到这样的问题,当我发送多个响应头时会触发此错误,但事实是我没有发送多个头。好像很奇怪
这是我的堆栈跟踪:
(节点:9236)DeprecationWarning:不建议使用当前的URL字符串解析器,并将在以后的版本中将其删除。要使用新的解析器,请将选项{useNewUrlParser:true}传递给MongoClient.connect。
服务器运行在端口5000
MongoDB的关联错误
[ERR_HTTP_HEADERS_SENT]:无法设置头后,他们被发送到客户端
在validateHeader(_http_outgoing.js:503:11)
在ServerResponse.setHeader(_http_outgoing.js:510:3)
在ServerResponse.header (/Users/lourdesroashan/code/github/devlog/node_modules/express/lib/response.js:767:10)
在ServerResponse.json(/ Users / lourdesroashan / code / github / devlog / node_modules / express / lib / response。 js:264:10
)
位于<anonymous> 上的Profile.findOne.then.profile(/Users/lourdesroashan/code/github/devlog/routes/api/profile.js:27:30)
这是我的服务器代码:
router.get("/userprofile", passport.authenticate('jwt', { session: false }), (req, res) => {
Profile.findOne({ user: req.user.id }).then(profile => {
if (!profile) {
return res.status(404).json({ error: "No Profile Found" });
}
else {
res.json(profile);
}
}).catch(err => {
console.log(err);
})
});
Run Code Online (Sandbox Code Playgroud)
我知道错误的含义,但是据我所知,我认为我没有发送多个标头,甚至通过console.log检查是否仅运行了一个块。
提前非常感谢您!:)
完整代码位于:https …
express-jwt ×10
jwt ×6
express ×4
node.js ×4
passport.js ×3
javascript ×2
access-token ×1
jquery ×1
jwt-auth ×1
mongodb ×1
mongoose ×1
npm ×1
security ×1