як реалізувати авторизацію входу в node.js


77

У мене запущений цей сервер вузлів:

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);
    }
});

Я хочу додати форму входу для цього сервера. Так що коли аутентифікація користувача буде показана.

   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;
    }    
}

у процесі запиту функція повертає файли клієнту, якщо жодна команда не дана, тому я можу надіслати команду входу з клієнта на сервер, але що повинен робити сервер, коли він отримує команду входу з паролем імені користувача, як він повинен передавати запит на вхід і повернути вхід успішний або невдалий, для написання цієї частини мені потрібна допомога.

що я пробував.

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);
    }
}

Будь ласка, підкажіть, як я можу додати сеанс у цьому, який я спробував додати, змінну запиту у функції входу та спробував встановити змінну request.session, в якій написано request.session не визначено.

Будь ласка, підкажіть, як я можу написати цей модуль входу, який може підтримувати автентифікацію входу належним чином для кожного користувача.


зроблено з підключенням: blog.nodejitsu.com/sessions-and-cookies-in-node
XMen

Відповіді:


247

Ось як я це роблю за допомогою Express.js :

1) Перевірте, чи аутентифіковано користувача : У мене є функція проміжного програмного забезпечення з іменем CheckAuth, яку я використовую на кожному маршруті, який потребує автентифікації користувача:

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

Я використовую цю функцію в своїх маршрутах так:

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

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) Маршрут виходу:

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

Якщо ви хочете дізнатись більше про Express.js, перевірте їхній веб-сайт тут: expressjs.com/en/guide/routing.html Якщо потрібні більш складні речі, перевірте всі автори (у ньому доступно багато методів автентифікації, для facebook, twitter тощо; хороший підручник з цього тут ).


1
У документації Express.js сказано, що для управління сеансами потрібно використовувати проміжне програмне забезпечення для підключення. Ваш код все ще актуальний?
nimrodm

1
Я думаю, що ти delete res.session.user_id;мала бути такою delete req.session.user_id;.
Йохан Кул

41
Це відмінне базове рішення. Одне, що я хотів би додати під час автентифікації, - це явно сказати браузеру не кешувати "обмежені" сторінки редагуванням заголовка відповіді. У цьому випадку, я хотів би додати res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');перед викликом next()в checkAuthметоді.
thauburger

3
Це заважає користувачеві отримати доступ до сторінки з обмеженим доступом, вийти з системи, а потім за допомогою кнопки "Назад" знову отримати доступ до сторінки з обмеженим доступом. Зміна політики кеш-пам’яті змушує сторінку повторно візуалізуватись, а checkAuthметод не вдається .
таубургер

4
@BRogers, ви можете використовувати вузол bcrypt для хешування паролів: github.com/ncb000gt/node.bcrypt.js
alessioalex

6

Насправді це насправді не відповідь на запитання, але це кращий спосіб це зробити.

Я пропоную вам скористатися connect / express як http-сервер, оскільки вони заощаджують вам багато часу. Ви, очевидно, не хочете винаходити колесо заново. У вашому випадку управління сеансом набагато простіше за допомогою connect / express.

Окрім цього для аутентифікації я пропоную вам використовувати кожну правду . Який підтримує безліч стратегій автентифікації. Чудово для швидкого розвитку.

Все це можна легко усунути, вставивши копію з їхньої документації!


3

Щоб додати до псевдовідповіді Фаріда,

Розгляньте можливість використання Passport.js над усіма авторами .

Відповіді на це питання дають деяке розуміння відмінностей.


Існує безліч переваг для завантаження автентифікації користувачів у Google, Facebook або інший веб-сайт. Якщо вимоги до вашої програми такі, що ви можете використовувати Passport як єдиного постачальника автентифікації або поряд із традиційним входом, це може полегшити досвід для ваших користувачів.


2

Відповідь @alessioalex - ідеальна демонстрація для нових користувачів вузлів. Але в будь-якому випадку важко записати проміжне програмне забезпечення checkAuth у всі маршрути, крім входу, тому краще перенести 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)

1

Я спробував цю відповідь, і вона не спрацювала для мене. Я також новачок у веб-розробці і ходив на заняття, де використовував mlab, але я віддаю перевагу синтаксичному аналізу, тому мені довелося шукати найбільш підходяще рішення. Ось моє власне поточне рішення з використанням синтаксичного аналізу на expressJS.

1) Перевірте, чи аутентифіковано користувача: у мене є функція проміжного програмного забезпечення з іменем isLogginIn, яку я використовую на кожному маршруті, який потребує автентифікації користувача:

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

Я використовую цю функцію в своїх маршрутах так:

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

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) Маршрут виходу:

 // 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');
   });

Це дуже добре спрацювало для мене, і я повністю посилався на документацію тут https://docs.parseplatform.org/js/guide/#users

Дякую @alessioalex за його відповідь. Я лише інформував про останні практики.


1

======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


0

Чому б не пошкодити мінімальний мінімальний модуль автентифікації?

SweetAuth

Легкий модуль автентифікації користувачів з нульовою конфігурацією, який не залежить від бази даних.

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

Це просто, як:

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
    }
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.