使用 nodejs Web 服务器但没有框架对用户进行身份验证

Posted

技术标签:

【中文标题】使用 nodejs Web 服务器但没有框架对用户进行身份验证【英文标题】:Authenticate a user using a nodejs web server but no framework 【发布时间】:2013-10-25 07:46:57 【问题描述】:

仍在尝试学习 javascript 和 nodejs。我到了在节点中有一个服务器的地步,它路由我的请求,回答我,查询 mysql 数据库,我认为效果很好!问题是,我需要一些方法来验证将成为只有一个能够在数据库中编辑、删除或创建记录。

应该是这样的: User1 - 浏览页面,所有选择查询,除了一些会增加访问计数器的查询 User2 - 管理员,无所不能

我调查并发现了几种方法,我不太了解它们,但它们似乎都需要我重写几乎所有的服务器!我使用了我认为是纯 nodejs 的东西,

var http = require("http"); 
var url = require("url");

我还使用 sequelize 连接到我的数据库。

调查我发现了这个: - http://passportjs.org/ 护照的问题是它适用于快递,我必须全部重写

expressjs 再次重写

http://mcavage.me/node-restify/ 而且我还发现了restify,它看起来很棒,但这意味着完全重写已经有效的东西。

nodejs 我似乎无法在 nodejs 文档中找到有关身份验证的内容。

我从未做过身份验证,如果不涉及数据库,我无法理解它们是如何工作的,我理解的身份验证是:用户登录,他的请求使用具有特定访问权限的 db 用户连接到数据库,我知道如何做数据库端,但是客户端和服务器之间在到达数据库之前发生的事情超出了我的范围。

我将发布所有资源,请随意跳过它们,希望它们能帮助那些想要做同样事情的人。

基本上,我认为唯一剩下的就是某种身份验证以及将图像从浏览器上传到服务器并将其保存在服务器中的能力。 我将实现一个 angularjs 客户端(我还没有学习),它将发出所有请求。

任何帮助将不胜感激!

index.js

var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = ;
handle["/insertHood"] = requestHandlers.insertHood;
handle["/selectHood"] = requestHandlers.selectHood;


server.start(router.route, handle);

server.js

var http = require("http");
var url = require("url"); //This module has utilities for URL resolution and parsing.  http://nodejs.org/api/all.html#all_url

function start(route, handle) 
    //the web service will respond with this
    function onRequest(request, response) 
        var urlValues = 
            params: ,
            pathName: ""
        ;
        var postData = "";

        //read the url used to call our web service
        parseUrl(request, urlValues);
        //console.log("path: " + urlValues.pathName);
        //console.log("params: " + JSON.stringify(urlValues.params));

        //set encoding for the recieved request
        request.setEncoding("utf8");

        //if post data is recieved process it here by chunks
        request.addListener("data", function (postDataChunk) 
            postData += postDataChunk;
            console.log("Recieved POST data chunk '" + postDataChunk + "'.");
        
        );

        //when we are done storing all the post data, go to the pathName
        request.addListener("end", function () 
            route(handle, urlValues, response, postData);
        
        );
    
    http.createServer(onRequest).listen(8888);
    console.log("Server has started");


function parseUrl(request, urlValues) 
    urlValues.pathName = url.parse(request.url).pathname; //parse the url pathName
    urlValues.params = url.parse(request.url, true).query;


exports.start = start;
exports.parseUrl = parseUrl;

路由器.js

function route(handle, urlValues, response, postData) 
    console.log("Router.js --> About to route a request for " + urlValues.pathName);
    if (typeof handle[urlValues.pathName] === 'function') 
        handle[urlValues.pathName](response, urlValues, postData);
     else 
        response.writeHead(404,  "Content-Type": "text/plain" );
        response.write("404, no request handler found for " + urlValues.pathName);
        response.end();
    


exports.route = route;

requesthandlers.js

var exec = require("child_process").exec;
var db = require("./dataBase");

function insertHood(response, urlValues) 
    urlValues.params["zoom_level"] = parseInt(urlValues.params["zoom_level"]);
    urlValues.params["lat"] = parseFloat(urlValues.params["lat"], 10);
    urlValues.params["lon"] = parseFloat(urlValues.params["lon"], 10);

    console.log("requestHandler.js --> Request handler 'insertHood' was called.");
    var result = db.execute("modify", 'INSERT INTO neighborhood (hood_location, hood_name, zoom_level) values (GeomFromText(\'POINT(:lat :lon)\'), :name, :zoom_level)', response, urlValues.params);


function selectHood(response, urlValues) 
    console.log("requestHandler.js --> Request handler 'selectHood' was called.");
    var result = db.execute("select", 'select x(hood_location), y(hood_location), hood_name, zoom_level from neighborhood where hood_name = :name', response, urlValues.params);


exports.insertHood = insertHood;
exports.selectHood = selectHood;

数据库.js

var Sequelize = require("sequelize");

//this tells sequelize how to connect to the data base
//see http://sequelizejs.com/documentation#usage-basics
var sequelize = new Sequelize('mydb', 'myuser', 'mypass',
    
        host: "localhost",
        port: 3306,
        dialect: 'mysql'
    
);

/*
Pre:
type: a string to know if the query is a select and returns rows, or a modify query, and returns nothing
query: an sql query in string format with the parameters :param in place
response: a response object where the results of the query will be written
parameters: from sequelize, an array with the parameter for the sql query in the correct order

Pos:
response: the object will have the results of the query, an error or the rows of the results set
*/
function execute(type, query, response, parameters) 
    console.log("Query: " + query); 
    var options =  raw: true ;

    var result = sequelize.query(query, null, options, parameters)
    .success(function (rows)         
        if (type == 'select') 
            response.writeHead(200,  "Content-Type": "application/json" );
            response.write(JSON.stringify(rows));
            response.end();
         else if (type == 'modify') 
            response.writeHead(200,  "Content-Type": "text/html" );
            response.write("Query was successful");
            response.end();
        
    
    ).error(function (e) 
        console.log("An error occured: ", e);
        response.writeHead(404,  "Content-Type": "text/html" );
        response.write("There was an error man, shits on fire yo ---> " + e);
        response.end();
    
    );


exports.execute = execute;

【问题讨论】:

【参考方案1】:

基本身份验证并不太难,即使没有外部框架。最困难的部分实际上只是正确维护会话。我强烈建议您为此使用session,但这不是必需的。 Connect 的会话在这里非常理想,因为它管理过期的会话,因此您不会拥有不断增加的对象。

为了维护身份验证,一旦用户输入了他们的凭据并将其发送到服务器,请与有效凭据进行交叉检查;如果它们匹配,那么您将需要在客户端存储一个具有唯一 UUID 的 cookie。在服务器端,保留一个包含所有经过身份验证的用户的哈希的对象。这样一来,一旦用户连接,服务器就可以检查他们是否已经有一个 cookie 来证明他们的凭据,这样您就不必在每个页面上都登录。

这样的事情在基本情况下应该可以工作:

路由:

var sessions =

if(req.headers.cookies['sid'] && sessions[req.headers.cookies['sid']])
    //continue
else
    //return login page

在用户登录时:

if(req.query.username == someUsername && req.query.password == somePassword)
      res.writeHead(200, 
          'Set-Cookie': 'sid=UUID', //will need a uuidgen here
          'Content-Type': 'text/plain'
      )
      sessions[UUID] = true //store session on server
      return res.send(200,somePage)

【讨论】:

感谢您的回答,您所说的给了我一些想法,但仍然没有得到一些东西,这就是我要做的:一旦用户登录,将他的凭据存储在 cookie 中。当他提出请求时,通过 POST 发送他的凭据并使用它们在数据库上进行身份验证。如果 cookie 没有凭据,那么他没有登录,我应该请他登录。每次发出请求时,我都会连接和断开与数据库的连接,这样可以吗?另外,在您的示例中,您如何知道要在哈希中检查谁的凭据?你如何管理数据库连接? @Toddy 在客户端存储用户凭据通常是不安全的,您没有理由需要这样做。散列的关键在于它是该特定用户在服务器上的验证状态的唯一标识符。每次请求都连接到数据库既费时又不必要。您应该只在服务器上保持数据库连接打开,并根据用户是否经过验证来决定是否允许读/写。

以上是关于使用 nodejs Web 服务器但没有框架对用户进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

NodeJs框架

Nodejs之使用express框架搭建WEB应用

如何用nodejs搭建mssql

支持多用户web终端实现及安全保障(nodejs)

Node.js学习8~10款基于nodejs的主流web框架排名及介绍

使用nodejs进行后端渲染,前端还需要框架级的工具吗