简体   繁体   English

使用令牌进行身份验证来标识后端和前端上的用户

[英]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.

相关问题 使用Vue.js和Auth0进行前端身份验证时如何在Django的后端数据库中创建用户 - How to create users in Django's backend database when using Vue.js and Auth0 for frontend authentication 前端应用程序和另一个后端服务使用的REST API的身份验证方法 - Authentication approach for REST API used by frontend app and another backend service 保护HTML / JavaScript前端和后端之间的请求(身份验证) - Securing requests between HTML/JavaScript-frontend and backend (authentication) 使用 chartjs、mongodb 和控制器的图表的前端和后端 - Frontend and backend for chart using chartjs, mongodb, and controller 使用 Expressjs 中间件进行功能切换 - 前端和后端 - Feature toggling using Expressjs middleware - frontend and backend 如何使用Node在IBM云功能内保存API用户身份验证令牌? - How can I save API user authentication tokens within IBM cloud functions using Node? 如果我在前端使用 vanilla js 而在后端使用 node.js,如何在同一端口上运行前端和后端? - How to run frontend and backend on same port , if I am using vanilla js on frontend and node js on backend? Angular 2 前端 django 2 REST 框架后端用户身份验证 - Angular 2 frontend django 2 REST framework backend user auth 后端和前端之间使用 CASL 库共享的用户授权 - User Authorization with CASL library share between backend and frontend 如何使用Google App Engine作为后端在Chrome扩展程序中实施用户身份验证? - How do I implement user authentication in a Chrome Extension using Google App Engine as backend?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM