[英]Identify a user on backend and frontend using tokens for authentication
I would like to create a simple Express API using Json Web Tokens. 我想使用Json Web令牌创建一个简单的Express API。 When the user tries to sign in I execute this 当用户尝试登录时,我执行此操作
exports.signIn = async (req, res, next) => {
const { username, password } = req.body;
// get user from database
const userQueryResult = await userQueries.getUserByName([username]);
// return if database errors occured
if (userQueryResult.err) {
res.status(500).json({
message: userQueryResult.err.message
});
}
const users = userQueryResult.result;
const user = users[0];
// no user found
if (!user) {
res.status(401).json({
message: 'Auth failed'
});
}
try {
// validate the password
const passwordMatch = bcrypt.compareSync(password, user.passwordHash);
// wrong credentials
if (!passwordMatch) {
res.status(401).json({
message: 'Auth failed'
});
}
const token = jwt.sign({
user.id
}, tokenSecret, {
tokenExpiration
});
res.status(200).json({
message: 'Auth succeeded',
token
});
} catch (err) {
res.status(401).json({
message: 'Auth failed'
});
}
};
A new token gets generated and is sent to the client. 生成一个新令牌并将其发送到客户端。 Do I have to send the user object to the client too? 我也必须将用户对象发送给客户端吗? Because currently I'm only checking if a user is authenticated but not which one. 因为当前我仅检查用户是否已通过身份验证,而不是哪个用户。
For protected routes I check if a user is authenticated by using a middleware function 对于受保护的路由,我检查是否通过使用中间件功能对用户进行了身份验证
module.exports = (req, res, next) => {
try {
const rawToken = req.headers.authorization; // bearer <token>
const token = rawToken.split(' ')[1]; // extract the token
req.userData = jwt.verify(token, tokenSecret); // verify this token
next();
} catch (error) {
res.status(401).json({
message: 'Auth failed'
});
}
}
So would you send the user id to the client too? 那么,您也会将用户ID发送给客户端吗? Do you store it to the local browser storage with the token and delete it when removing the token? 您是否将其与令牌一起存储到本地浏览器存储中,并在删除令牌时将其删除?
Maybe I got it wrong but currently I only know how to check if someone is authenticated but not which one. 也许我弄错了,但目前我只知道如何检查某人是否已通过身份验证,而不是哪一个。 The client needs to know which user is currently signed in. 客户端需要知道当前登录的用户。
A new token gets generated and is sent to the client. 生成一个新令牌并将其发送到客户端。 Do I have to send the user object to the client too? 我也必须将用户对象发送给客户端吗? Because currently I'm only checking if a user is authenticated but not which one. 因为当前我仅检查用户是否已通过身份验证,而不是哪个用户。
Technically you could send also user object (and any other info), but generally what you want to send back is only jwt token, since it has all the information (payload) inside that you need on your client side. 从技术上讲,您还可以发送用户对象(以及任何其他信息),但是通常您要发回的只是jwt令牌,因为它具有客户端需要的所有内部信息(有效负载)。
So would you send the user id to the client too? 那么,您也会将用户ID发送给客户端吗?
Same as previous answer, if you need user id on the client side, you include it into jwt payload. 与先前的答案相同,如果在客户端需要用户ID,则将其包含在jwt有效负载中。
Do you store it to the local browser storage with the token and delete it when removing the token? 您是否将其与令牌一起存储到本地浏览器存储中,并在删除令牌时将其删除?
If you need it as something permanent (page reload) them yes, save jwt token or anything else for that matter into the local storage. 如果需要将其作为永久性文件(重新加载页面),则可以,将jwt令牌或与此相关的任何其他内容保存到本地存储中。
Maybe I got it wrong but currently I only know how to check if someone is authenticated but not which one. 也许我弄错了,但目前我只知道如何检查某人是否已通过身份验证,而不是哪一个。 The client needs to know which user is currently signed in. 客户端需要知道当前登录的用户。
What you are looking for is user authorization (not authentication) which you check on the server side. 您正在寻找的是在服务器端检查的用户授权(不是身份验证)。
You got two options: 您有两种选择:
1) You could store the user in the JWT. 1)您可以将用户存储在JWT中。
Through that you can easily access it on the backend when another request comes in (not on the frontend though, as JWTs are encrypted). 这样,当另一个请求进入时,您可以在后端轻松访问它(但是,由于JWT被加密,因此不在前端)。 This might be faster than looking up the user every time. 这可能比每次查找用户都要快。 However you'd have to send the user to the frontend and back again on every request done, which slows things down, also you copy the data, and if the database record changed you won't notice 但是,您必须将用户发送到前端,然后在完成每个请求后再次返回,这会减慢速度,还需要复制数据,并且如果数据库记录已更改,您将不会注意到
2) Store a user or session id in the JWT, then look that up in a database / in memory Map to get the user. 2)将用户或会话ID存储在JWT中,然后在数据库/内存Map中查找以获取用户。 While the database gets used mkre with this, you save bandwith and keep track with changes. 在数据库对此进行使用的同时,您可以节省带宽并跟踪更改。
// on login
const token = jwt.sign({ id: user.id }, tokenSecret, { tokenExpiration });
// or
const token = jwt.sign({ user }, tokenSecret, { tokenExpiration });
To then be able to show the data of the user on the client, you have to send it in an unencrypted way, eg: 为了能够在客户端上显示用户的数据,您必须以未加密的方式发送它,例如:
res.send(`Your name is ${user.name} and you got the id ${user.id}`);
I try to answer your questions: 我尝试回答您的问题:
Do I have to send the user object to the client too? 我也必须将用户对象发送给客户端吗?
it depends if you need user you can send it. 这取决于您是否需要用户才能发送。 I usually store user object in req.user
by creating a middleware eg authMiddleware like this: 我通常通过创建中间件(例如authMiddleware)将用户对象存储在req.user
,如下所示:
const { User } = require('../models/user');
let authenticate = function (req, res, next) {
let token = req.cookies.access_token;
User.findByToken(token).then((user) => {
req.user = user;
req.token = token;
next();
}).catch(e => {
res.redirect('/');
})
}
module.exports = {
authenticate
}
i assume you use mongodb and mongoose. 我假设您使用mongodb和mongoose。 what is findByToken() method? 什么是findByToken()方法? it's custom mongoose model method: 这是自定义猫鼬模型方法:
// user model
const mongoose = require('mongoose');
let UserSchema = new mongoose.Schema({
...your model schema,
tokens: [{ //here is tokens array
access: {
type: String,
required: true
},
token: {
type: String,
required: true
}
}],
}
UserSchema.statics.findByToken = function (token) {
let user = this;
let decoded;
try {
decoded = jwt.verify(token, 'secret')
} catch (e) {
return Promise.reject();
}
return user.findOne({
'_id': decoded._id,
'tokens.access': 'auth',
'tokens.token': token
})
}
let User = mongoose.model('User', UserSchema);
module.exports = { User };
So would you send the user id to the client too? 那么,您也会将用户ID发送给客户端吗? Do you store it to the local browser storage with the token and delete it when removing the token? 您是否将其与令牌一起存储到本地浏览器存储中,并在删除令牌时将其删除?
after singing a token you must store token in tokens Array of user model document 唱歌令牌后,必须将令牌存储在令牌中用户模型文档的数组
UserSchema.methods.generateAuthToken = function () {
let user = this;
let access = 'auth';
let token = jwt.sign({ '_id': user._id.toHexString(), access }, 'secret').toString();
user.tokens = user.tokens.concat([{ access, token }]);
return user.save().then(() => {
return token;
})
}
it's recommended to store token in the cookie: 建议将令牌存储在cookie中:
res.cookie('access_token', token, {
maxAge: 3600000,
httpOnly: true
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.