如何在 node.js 中实现登录身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7990890/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:43:44  来源:igfitidea点击:

how to implement login auth in node.js

authenticationnode.jslogin

提问by XMen

I have this node server running :

我有这个节点服务器运行:

var server=http.createServer(function(request, responsehttp) {
    if (request.method == 'POST') {
        var body = '';
        request.on('data', function (data) {
            body += data;
        });
        request.on('end', function () {
            var POST = qs.parse(body);
            processquery(POST, request, responsehttp);
        });
    } else {
        var url_parts = url.parse(request.url, true);
        var query = url_parts.query;
        console.log(query);
        processquery(query, request, responsehttp);
    }
});

I want to add login form for this server .so when user is authenticated then it will show .

我想为此服务器添加登录表单。因此,当用户通过身份验证时,它将显示 .

   function processquery(query, request, responsehttp){
    var returnResult = function (data){
        responsehttp.end(JSON.stringify(data));
    };

    if (!query.command) {
        fileprocess(request, responsehttp);
    }
    responsehttp.writeHead(200, {"Content-Type": "application/json"});
    switch(query.command) {
        case 'logout':
            logout(query, returnResult);
            break;
        case 'login':
            login(query, returnResult);
            break;
    }    
}

in process query function returning the files to client if any command is not given , so i can send the login command from client to server , but what server should do when it recieve the login command with username password , how it should hand the login request and return the login sucess or failure, for writing this part i need help .

如果没有给出任何命令,进程中查询函数将文件返回给客户端,因此我可以将登录命令从客户端发送到服务器,但是当服务器收到带有用户名密码的登录命令时应该做什么,它应该如何处理登录请求并返回登录成功或失败,为了编写这部分我需要帮助。

what i tried .

我试过的。

function login(request, callback) {
    if(request.username==users[request.username] && request.password==users[request.username].password) {
        users[request.username].auth=true;
        var data = {result:'success','message':'login successful'};
        callback(data);
    } else {
        var data = {result:'error','message':'login incorrect'};
        callback(data);
    }
}

Please suggest how can i add session in this i tried adding , request variable in login function and tried setting request.session variable it says request.session is undefined .

请建议我如何在此添加会话我尝试在登录函数中添加请求变量并尝试设置 request.session 变量它说 request.session 是未定义的。

Please suggest how can i write this login module which can maintain login authentication properly for every user .

请建议我如何编写这个登录模块,它可以为每个用户正确维护登录身份验证。

回答by alessioalex

Here's how I do it with Express.js:

这是我使用Express.js 的方法

1) Check if the user is authenticated: I have a middleware function named CheckAuth which I use on every route that needs the user to be authenticated:

1)检查用户是否已通过身份验证:我有一个名为 CheckAuth 的中间件函数,我在需要对用户进行身份验证的每条路由上使用它:

function checkAuth(req, res, next) {
  if (!req.session.user_id) {
    res.send('You are not authorized to view this page');
  } else {
    next();
  }
}

I use this function in my routes like this:

我在我的路线中使用这个功能是这样的:

app.get('/my_secret_page', checkAuth, function (req, res) {
  res.send('if you are viewing this page it means you are logged in');
});

2) The login route:

2)登录路径:

app.post('/login', function (req, res) {
  var post = req.body;
  if (post.user === 'john' && post.password === 'johnspassword') {
    req.session.user_id = johns_user_id_here;
    res.redirect('/my_secret_page');
  } else {
    res.send('Bad user/pass');
  }
});

3) The logout route:

3)登出途径:

app.get('/logout', function (req, res) {
  delete req.session.user_id;
  res.redirect('/login');
});      

If you want to learn more about Express.js check their site here: expressjs.com/en/guide/routing.htmlIf there's need for more complex stuff, checkout everyauth(it has a lot of auth methods available, for facebook, twitter etc; good tutorial on it here).

如果您想了解有关 Express.js 的更多信息,请在此处查看他们的网站:expressjs.com/en/guide/routing.html如果需要更复杂的东西,请查看everyauth(它有很多可用的身份验证方法,适用于 facebook、twitter等等;这里有很好的教程)。

回答by Farid Nouri Neshat

Actually this is not really the answer of the question, but this is a better way to do it.

实际上,这并不是问题的真正答案,但这是一个更好的方法。

I suggest you to use connect/expressas http server, since they save you a lot of time. You obviously don't want to reinvent the wheel. In your case session management is much easier with connect/express.

我建议您使用connect/ express作为 http 服务器,因为它们可以为您节省大量时间。你显然不想重新发明轮子。在您的情况下,使用 connect/express 进行会话管理要容易得多。

Beside that for authentication I suggest you to use everyauth. Which supports a lot of authentication strategies. Awesome for rapid development.

除此之外,我建议您使用everyauth进行身份验证。它支持很多身份验证策略。非常适合快速开发。

All this can be easily down with some copy pasting from their documentation!

所有这些都可以通过从他们的文档中复制粘贴来轻松解决!

回答by Luke

To add to Farid's pseudo-answer,

添加到 Farid 的伪答案,

Consider using Passport.jsover everyauth.

考虑在everyauth 上使用Passport.js

The answers to this questionprovide some insight to the differences.

这个问题的答案提供了一些差异的见解。



There are plenty of benefits to offloading your user authentication to Google, Facebook or another website. If your application's requirements are such that you could use Passport as your sole authentication provider or alongside traditional login, it can make the experience easier for your users.

将您的用户身份验证卸载到 Google、Facebook 或其他网站有很多好处。如果您的应用程序要求您可以使用 Passport 作为您唯一的身份验证提供程序或与传统登录一起使用,那么它可以使您的用户体验更轻松。

回答by Chang

@alessioalex answer is a perfect demo for fresh node user. But anyway, it's hard to write checkAuth middleware into all routes except login, so it's better to move the checkAuth from every route to one entry with app.use. For example:

@alessioalex 答案是新节点用户的完美演示。但是无论如何,很难将 checkAuth 中间件写入除 login 之外的所有路由中,因此最好将 checkAuth 从每个路由移动到 app.use 的一个条目。例如:

function checkAuth(req, res, next) {
  // if logined or it's login request, then go next route
  if (isLogin || (req.path === '/login' && req.method === 'POST')) {
    next()
  } else {
    res.send('Not logged in yet.')
  }
}

app.use('/', checkAuth)

回答by felix

I tried this answer and it didn't work for me. I am also a newbie on web development and took classes where i used mlab but i prefer parse which is why i had to look for the most suitable solution. Here is my own current solution using parse on expressJS.

我试过这个答案,但对我不起作用。我也是网络开发的新手,并参加了我使用 mlab 的课程,但我更喜欢解析,这就是为什么我必须寻找最合适的解决方案。这是我自己在 expressJS 上使用解析的当前解决方案。

1)Check if the user is authenticated: I have a middleware function named isLogginIn which I use on every route that needs the user to be authenticated:

1)检查用户是否通过身份验证:我有一个名为 isLogginIn 的中间件函数,我在需要用户身份验证的每条路由上使用它:

 function isLoggedIn(req, res, next) {
 var currentUser = Parse.User.current();
 if (currentUser) {
     next()
 } else {
     res.send("you are not authorised");
 }
}

I use this function in my routes like this:

我在我的路线中使用这个功能是这样的:

  app.get('/my_secret_page', isLoggedIn, function (req, res) 
  {
    res.send('if you are viewing this page it means you are logged in');
  });

2) The Login Route:

2)登录路径:

  // handling login logic
  app.post('/login', function(req, res) {
  Parse.User.enableUnsafeCurrentUser();
  Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
    res.redirect('/books');
  }, function(error) {
    res.render('login', { flash: error.message });
  });
});

3) The logout route:

3) 登出途径:

 // logic route
  app.get("/logout", function(req, res){
   Parse.User.logOut().then(() => {
    var currentUser = Parse.User.current();  // this will now be null
    });
        res.redirect('/login');
   });

This worked very well for me and i made complete reference to the documentation here https://docs.parseplatform.org/js/guide/#users

这对我来说非常有效,我完全参考了此处的文档 https://docs.parseplatform.org/js/guide/#users

Thanks to @alessioalex for his answer. I have only updated with the latest practices.

感谢@alessioalex 的回答。我只更新了最新的做法。

回答by semua bisa

======authorization====== MIDDLEWARE

const jwt = require('../helpers/jwt')
const User = require('../models/user')

module.exports = {
  authentication: function(req, res, next) {
    try {
      const user = jwt.verifyToken(req.headers.token, process.env.JWT_KEY)
      User.findOne({ email: user.email }).then(result => {
        if (result) {
          req.body.user = result
          req.params.user = result
          next()
        } else {
          throw new Error('User not found')
        }
      })
    } catch (error) {
      console.log('langsung dia masuk sini')

      next(error)
    }
  },

  adminOnly: function(req, res, next) {
    let loginUser = req.body.user
    if (loginUser && loginUser.role === 'admin') {
      next()
    } else {
      next(new Error('Not Authorized'))
    }
  }
}

====error handler==== MIDDLEWARE
const errorHelper = require('../helpers/errorHandling')

module.exports = function(err, req, res, next) {
  //   console.log(err)
  let errorToSend = errorHelper(err)
  // console.log(errorToSend)
  res.status(errorToSend.statusCode).json(errorToSend)
}


====error handling==== HELPER
var nodeError = ["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]
var mongooseError = ["MongooseError","DisconnectedError","DivergentArrayError","MissingSchemaError","DocumentNotFoundError","MissingSchemaError","ObjectExpectedError","ObjectParameterError","OverwriteModelError","ParallelSaveError","StrictModeError","VersionError"]
var mongooseErrorFromClient = ["CastError","ValidatorError","ValidationError"];
var jwtError = ["TokenExpiredError","JsonWebTokenError","NotBeforeError"]

function nodeErrorMessage(message){
    switch(message){
        case "Token is undefined":{
            return 403;
        }
        case "User not found":{
            return 403;
        }
        case "Not Authorized":{
            return 401;
        }
        case "Email is Invalid!":{
            return 400;
        }
        case "Password is Invalid!":{
            return 400;
        }
        case "Incorrect password for register as admin":{
            return 400;
        }
        case "Item id not found":{
            return 400;
        }
        case "Email or Password is invalid": {
            return 400
        }
        default :{
            return 500;
        }
    }
}

module.exports = function(errorObject){
    // console.log("===ERROR OBJECT===")
    // console.log(errorObject)
    // console.log("===ERROR STACK===")
    // console.log(errorObject.stack);

    let statusCode = 500;  
    let returnObj = {
        error : errorObject
    }
    if(jwtError.includes(errorObject.name)){
        statusCode = 403;
        returnObj.message = "Token is Invalid"
        returnObj.source = "jwt"
    }
    else if(nodeError.includes(errorObject.name)){
        returnObj.error = JSON.parse(JSON.stringify(errorObject, ["message", "arguments", "type", "name"]))
        returnObj.source = "node";
        statusCode = nodeErrorMessage(errorObject.message);
        returnObj.message = errorObject.message;
    }else if(mongooseError.includes(errorObject.name)){
        returnObj.source = "database"
        returnObj.message = "Error from server"
    }else if(mongooseErrorFromClient.includes(errorObject.name)){
        returnObj.source = "database";
        errorObject.message ? returnObj.message = errorObject.message : returnObj.message = "Bad Request"
        statusCode = 400;
    }else{
        returnObj.source = "unknown error";
        returnObj.message = "Something error";
    }
    returnObj.statusCode = statusCode;
    
    return returnObj;


}


===jwt====
const jwt = require('jsonwebtoken')

function generateToken(payload) {
    let token = jwt.sign(payload, process.env.JWT_KEY)
    return token
}

function verifyToken(token) {
    let payload = jwt.verify(token, process.env.JWT_KEY)
    return payload
}

module.exports = {
    generateToken, verifyToken
}

===router index===
const express = require('express')
const router = express.Router()

// router.get('/', )
router.use('/users', require('./users'))
router.use('/products', require('./product'))
router.use('/transactions', require('./transaction'))

module.exports = router

====router user ====
const express = require('express')
const router = express.Router()
const User = require('../controllers/userController')
const auth = require('../middlewares/auth')

/* GET users listing. */
router.post('/register', User.register)
router.post('/login', User.login)
router.get('/', auth.authentication, User.getUser)
router.post('/logout', auth.authentication, User.logout)
module.exports = router


====app====
require('dotenv').config()
const express = require('express')
const cookieParser = require('cookie-parser')
const logger = require('morgan')
const cors = require('cors')
const indexRouter = require('./routes/index')
const errorHandler = require('./middlewares/errorHandler')
const mongoose = require('mongoose')
const app = express()

mongoose.connect(process.env.DB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useCreateIndex: true,
  useFindAndModify: false
})

app.use(cors())
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())

app.use('/', indexRouter)
app.use(errorHandler)

module.exports = app

回答by Naveen

Why not disecting a bare minimum authentication module?

为什么不剖析一个最低限度的身份验证模块?

SweetAuth

SweetAuth

A lightweight, zero-configuration user authentication module which doesn't depend on a database.

一个轻量级、零配置的用户身份验证模块,不依赖于数据库。

https://www.npmjs.com/package/sweet-auth

https://www.npmjs.com/package/sweet-auth

It's simple as:

这很简单:

app.get('/private-page', (req, res) => {

    if (req.user.isAuthorized) {
        // user is logged in! send the requested page
        // you can access req.user.email
    }
    else {
        // user not logged in. redirect to login page
    }
})