我在服务器上使用NodeJ,我需要添加一些基本的auth功能,在任何文件(如html或js文件)下载到用户的浏览器之前,它会询问用户凭据。当我在没有登录时尝试查看源代码时,我无法像在this中那样访问它。
这适用于basic-auth
模块,但仅适用于一个用户名和密码。
app.use(basicAuth('username', 'password'));
并且存在问题 - 我需要从数据库加载此credentions并检查用户是否为admin并比较他的加密密码。 我试过这个:
// ****
var basicAuth = require('basic-auth');
// ****
app.use(function (req, res, next) {
var user = basicAuth(req);
if (user) {
var c = mysql.createConnection(db);
var q = "SELECT * FROM user WHERE email = '" + user.name + "' AND admin = 1;";
c.query(q, function (error, result) {
c.end();
if (error) {
console.log(error);
res.set('WWW-Authenticate', 'Basic realm="example"');
return res.status(401).send();
} else {
if (result.length === 1 &&
bcrypt.compareSync(user.pass, result[0].password)) {
return next();
} else {
res.set('WWW-Authenticate', 'Basic realm="example"');
return res.status(401).send();
}
}
});
} else {
res.set('WWW-Authenticate', 'Basic realm="example"');
return res.status(401).send();
}
});
这样可以正常工作,但每次浏览器与服务器通信时都会调用此函数,这在加载简单页面时大约是70次(它不会再次要求用户提供凭据,&#34;只有&# 34;运行此功能)。此功能在每个请求上持续约200毫秒(因为查询和密码比较),总计加载持续 15秒,不可接受。< /强>
有人可以帮助我,如何解决这个问题或推荐一些其他NodeJs库,这可以帮助我吗?
谢谢。
答案 0 :(得分:0)
因此,如果您在数据库中存储哈希值并在数据库中存储管理员标志,那么为什么不执行以下选择请求:
var q = "SELECT * FROM user WHERE email = '" + user.name + "' AND password = '" + bcrypt.hashSync(user.pass) + "' AND admin = '1';";
如果只得到一个结果就可以,否则会被拒绝......
答案 1 :(得分:0)
如果我理解您的问题,则每次向服务器发出的请求都会运行您的身份验证,从而导致页面加载速度变慢。如果所有路线都在您正在进行的基本验证检查之后,我不明白某人如何登录,但这不是重点。
我设置节点应用程序的方法是为auth创建一系列函数,并将这些函数传递到我需要身份验证的特定路由,这样就可以为我可能正在服务的每个资源运行它。例如(psuedocode-ish):
// this is the authentication function array, each function in the array
// will be run when this array is called on a route, require next()
// after successful auth to continue on through the array/route handlers
// for your example, adminAuth would be the anonymous
// function in your app.use method
var auth = [adminAuth];
// some random route examples
// this is an unprotected route
app.get('/login', loginHandler);
// these are protected routes and will have auth called
app.get('/api/users', auth, getUserHandler);
app.post('/api/user', auth, postUserHandler);
总而言之,您只能将auth调用放在受保护的资源上,这样就可以在不进行每次运行auth检查的情况下提供图像,html,js,css等。
答案 2 :(得分:0)
您的代码存在一些问题。我知道您需要对每个请求进行密码检查,但您不一定每次都需要访问数据库。假设你必须做HTTP Basic(不再推荐,我希望你是这样,你是通过HTTPS做的),那么你可以做的一个重大改进就是你创造了某种快速数据缓存。最简单的形式是内存(假设您的应用程序的每个实例保持自己的副本都可以),但您也可以根据您的使用情况使用memcached或redis等内容。
一个非常简单的实现就是保持一个内存中的JS对象,其密钥等于用户名,并且值等于从db返回的数据。类似的东西:
var userCache = {}; // something local to the module is the easiest way
然后,当您要查询数据库时,只需先检查userCache
:
if(userCache[user.name]) // check password
else
// do your query and insert a successful result into the userCache for later.
这样做可以显着减少每个资源的响应时间,但对于生产解决方案,您可能需要多层缓存(例如,内存缓存和redis或memcached缓存,以帮助跨多个实例的性能)你的应用)。
其次,您应该使用bcrypt检查的回调版本。在给定的请求上它不会更快,但它可能会为您的应用程序提供更多的整体请求容量,这应该会有所帮助。
第三,由于三个原因,您的实际SQL查询是个坏主意。首先,在大多数数据库中,使用SELECT *
与选择所需的特定字段相比,性能会更差。这既是数据库端(查询缓存优化),也是节点端(例如,处理字符串响应和JS对象之间转换/转换的字段的时间)。其次,您正在进行的字符串连接是对SQL Injection attacks的邀请。请查看使用参数化查询。最后,如果您知道您的用户将是唯一的,那么您还应该在查询中添加LIMIT 1
,因为您只需要一个结果,并且数据库可以再次对其进行一些优化。