SocketIO + MySQL 认证 [英] SocketIO + MySQL Authentication
问题描述
我正在尝试通过 socketIO 对 MySQL 数据库进行身份验证.我已经建立了连接并且可以毫无问题地查询结果,但是由于某种原因,我无法将用户是否通过身份验证传递到 socketio 的 connection
部分.这个想法是我的应用程序有主机和查看器.如果连接到应用程序而未在 QueryString
中发送密码,则应用程序假定其为查看器并接受连接.如果发送了密码,则会根据 DB 进行检查并接受/拒绝连接.我想要一个变量传递到 connection
以便我可以在我的应用程序事件中使用它.这是我到目前为止所拥有的,但显然 data.query['ishost']
没有传递到应用程序中.
I am trying to authenticate over a MySQL DB via socketIO. I have established the connection and can query results without an issue, but for some reason I cannot pass whether or not the user is authenticated into the connection
part of socketio. The idea is my app has hosts and viewers. If connecting to the app without sending a password in the QueryString
the app assumes its a viewer and accepts connection. If a password is sent, it is checked against the DB and accepts/rejects the connection. I want a variable to pass into the connection
so I can use it inside of my apps events. Here's what I have so far but apparently the data.query['ishost']
isn't passing into the app.
sio.configure(function() {
sio.set('authorization', function (data, accept) {
UserID = data.query['username'];
try {
UserID = UserID.toLowerCase();
} catch(err) {
return accept("No WebBot Specified. ("+err+")", false);
}
// if not sending a password, skip authorization and connect as a viewer
if (data.query['password'] === 'undefined')
{
return accept(null, true);
}
// if sending a password, attempt authorization and connect as a host
else
{
client.query(
'SELECT * FROM web_users WHERE username = "'+UserID+'" LIMIT 1',
function selectCb(err, results, fields) {
if (err) {
throw err;
}
// Found match, hash password and check against DB
if (results.length != 0)
{
// Passwords match, authenticate.
if (hex_md5(data.query['password']) == results[0]['password'])
{
data.query['ishost'] = true;
accept(null, true);
}
// Passwords don't match, do not authenticate
else
{
data.query['ishost'] = false;
return accept("Invalid Password", false);
}
}
// No match found, add to DB then authenticate
else
{
client.query(
'INSERT INTO web_users (username, password) VALUES ("'+UserID+'", "'+hex_md5(data.query['password'])+'")', null);
data.query['ishost'] = "1";
accept(null, true);
}
client.end();
}
);
// Should never reach this
return accept("Hacking Attempt", false);
}
// Definitely should never reach this
return accept("Hacking Attempt", false);
});
});
写入data.query
使其可通过handshakeData 访问.但由于某种原因,它没有通过应用程序传递它.感谢您提供任何帮助,谢谢.
Writing to the data.query
makes it accessible through handshakeData. But for some reason its not passing it through the app. Any help is appreciated, thank you.
推荐答案
虽然我建议设置请求标头而不是设置查询字符串参数,但您已经很接近了.您的授权函数中的 data
变量是握手数据,其中包含您可以使用的请求标头和 cookie 信息.这是设置 cookie 的示例:
You're close, though I'd recommend setting a request header over setting a query string param. The data
variable in your authorization function is handshake data that contains request header and cookie information you can use. Here's an example with setting a cookie:
在服务器上
io.configure(function() {
io.set('authorization', function(handshake, callback) {
var cookie, token, authPair, parts;
// check for headers
if (handshake.headers.cookie &&
handshake.headers.cookie.split('=')[0]=='myapp') {
// found request cookie, parse it
cookie = handshake.headers.cookie;
token = cookie.split(/s+/).pop() || '';
authPair = new Buffer(token, 'base64').toString();
parts = authPair.split(/:/);
if (parts.length>=1) {
// assume username & pass provided, check against db
// parts[0] is username, parts[1] is password
// .... {db checks}, then if valid....
callback(null, true);
} else if(parts.length==1) {
// assume only username was provided @ parts[0]
callback(null,true);
} else {
// not what we were expecting
callback(null, false);
}
}
else {
// auth failed
callback(null, false);
}
});
});
在客户端
在调用 socket.connect
之前,使用您的身份验证/用户信息设置 cookie:
Before you call socket.connect
, set a cookie with your auth / user info:
function writeCookie(value, days) {
var date, expires;
// days indicates how long the user's session should last
if (days) {
date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
expires = "; expires="+date.toGMTString();
} else {
expires = "";
}
document.cookie = "myapp="+Base64.encode(value)+expires+"; path=/";
};
// for a 'viewer' user:
writeCookie('usernameHere', 1);
// for the 'host' user:
writeCookie('usernameHere:passwordHere', 1);
除非您的浏览器支持 ,否则您需要在客户端使用 Base64 库btoa()
.
You'll need a Base64 library on the client side unless your browser supports btoa()
.
需要注意的是,这不是一个好的身份验证结构.直接在查询字符串或标头信息中传递用户凭据是不安全的.不过,这种方法可以让您更接近一种更安全的方法.我建议查看像passport.js 或everyauth 这样的auth 库.您可以嵌入此代码以利用这些库存储的会话信息来运行您的检查.
It's important to note that this isn't a good authentication structure. Passing user credentials straight in either query strings or header information is not secure. This method gets you closer to a more secure method, though. I'd recommend looking into an auth library like passport.js or everyauth. You can sub-in this code to utilize the session information those libraries store in running your checks.
这篇关于SocketIO + MySQL 认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!