从Discuz迁移帐号密码到NodeBB
最近论坛要从Discuz改版到NodeBB中,由于原有dz框架使用了较长时间,积累了一定的用户数,为了对用户进行无感知的迁移,首先需要将账户登录的问题解决。
1. Discuz的加密方式
由于是从dz迁移到nodebb,所以得先了解dz的加密方式是如何实现的。 dz的加密方式比较简单,参考以下步骤:
1.首先密码明文pwd=123456,salt=666666(数据库中存放);
pwd=123456,salt=666666
2.对pwd进行一次md5,取32位小写结果hash1;
hash1=md5(pwd)
3.将hash1与salt进行拼接得到temp=hash1+salt;
temp=hash1+salt
4.对temp进行一次md5,取32为小写结果,即为数据库中的password字段。
password=md5(temp)
知道了dz的加密方式,下面就可以修改nodebb了
2. 修改Nodebb的注册和登录流程
主要涉及的文件有
1. `src/controllers/authentication.js`
2. `/src/bcrypt.js`
3. `/src/password.js`
4. `/src/user/create.js`
1.首先在注册的时候向数据库中同时存储salt字段,初始的salt最好与账户有一定关联,方便后续修改mongo数据库进行查询和修改(/src/user/create.js
)
async.parallel([
async.apply(User.setUserField, userData.uid, 'password', hash),
// 在用户进行注册的时候向User信息中增加salt字段,以便与dz的加密方式结合
async.apply(User.setUserField, userData.uid, 'salt','123456'),
async.apply(User.reset.updateExpiry, userData.uid),
],
next
)
2.修改/src/bcrypt.js
文件
process.on('message', function (msg) {
if (msg.type === 'hash') {
hashPasswordAsDz(msg.password, msg.salt, done);
} else if (msg.type === 'compare') {
compare(String(msg.password || ''), String(msg.hash || ''), msg.salt, done);
}
});
//修改对密码的加密方式为dz的加密方式
function hashPasswordAsDz(password, salt) {
var md5 = crypto.createHash('md5');
md5.update(password);
var hash1 = md5.digest('hex');
md5 = crypto.createHash('md5');
var content = hash1 + salt;
md5.update(content);
var hash2 = md5.digest('hex');
done(null, hash2)
}
//修改比较密码时的逻辑,与dz保持一致
function compare(password, hash, salt, done) {
var md5 = crypto.createHash('md5');
md5.update(password);
var hash1 = md5.digest('hex');
md5 = crypto.createHash('md5');
var content = hash1 + salt;
md5.update(content);
var hash2 = md5.digest('hex');
if (hash2==hash)
done(null, true);
else done(null, false);
}
function done(err, result) {
if (err) {
process.send({err: err.message});
return process.disconnect();
}
process.send({result: result});
process.disconnect();
}
3.修改/src/controllers/authentications.js
userData: function (next) {
db.getObjectFields('user:' + uid, ['password', 'passwordExpiry','salt'], next);
},
在进行login的时候,额外提取salt值,便于后续传递给compare函数进行md5的计算。
function (next) {
Password.compare(password, userData.password, userData.salt,next);
}
修改compare的参数列表,将userData中的salt也传递进去。
4.修改/src/password.js
function compare(password, hash,salt, callback) {
getFakeHash(function (err, fakeHash) {
if (err) {
return callback(err);
}
forkChild({ type: 'compare', password: password, hash: hash || fakeHash ,salt:salt}, callback);
});
}
修改为增加salt参数后的compare函数,这是调用bcrypt.js中的compare函数,并进行回调。
3.NodeBB小批量注册。
因为原论坛的数据量较小,且没有太多的时间去解析NodeBB的逻辑,所以采用最简单暴力的方法,通过selenium+pyvirtualdisplay来进行批量注册。帐号名和邮箱是dz里的数据,password随意,因为步骤4要改的。
def register(s_email, s_username, s_password):
display = Display(visible=0, size=(800, 600))
display.start()
browser = webdriver.Chrome()
browser.get(config.FORUM_HOME_URL)
time.sleep(2)
register = browser.find_element_by_xpath('//*[@id="logged-out-menu"]/li[1]/a');
register.click();# 打开注册页面
time.sleep(2)
browser.refresh()
# 获取注册列表项
email = browser.find_element_by_id('email')
username = browser.find_element_by_id('username')
password = browser.find_element_by_id('password')
password_confirm = browser.find_element_by_id('password-confirm')
register = browser.find_element_by_id('register')
# 填充值
email.send_keys(s_email)
username.send_keys(s_username)
password.send_keys(s_password)
password_confirm.send_keys(s_password)
register.click()
time.sleep(3)
browser.refresh()
# 获取协议同意按钮并提交
aggree1 = browser.find_element_by_id('gdpr_agree_data')
aggree2 = browser.find_element_by_id('gdpr_agree_email')
submit = browser.find_element_by_xpath('//*[@id="content"]/form/div[2]/div/button')
aggree1.click()
aggree2.click()
submit.click()
time.sleep(3)
大概跑了半天的时间注册完成,然后开始修改mongodb数据库中的内容,来完成最后一步
4.修改NodeBB数据源
现在跑完步骤3其实可以使用我们设置的初始密码登陆,但是本意是迁移dz到NodeBB中,所以还需要修改NodeBB的数据库,这里以mongodb为例。
1.查看mongodb数据库里的内容,发现主要与一个文档有关。 2.
{
"_id": "id",
"_key": "user:1",
"acceptTos": 0,
"banned": 0,
"birthday": "",
"email": "cc.zhang1024@gmail.com",
"fullname": "",
"gdpr_consent": 1,
"joindate": 1528885781389,
"lastonline": 1529026648838,
"lastposttime": 0,
"location": "",
"picture": "",
"postcount": 0,
"profileviews": 0,
"reputation": 0,
"signature": "",
"status": "online",
"topiccount": 0,
"uid": 1,
"uploadedpicture": "",
"username": "cc.zhang",
"userslug": "cc-zhang",
"website": "",
"password": "password",
"salt": "salt",
"passwordExpiry": 0
}
其中_key='user:'+user.id,我们要做的就是找到相关的user账户然后修改其salt为dz导出的salt,以及修改password为dz导出的password即可。
data.update({'email': email, 'salt': old_salt}, {'$set': {'salt': new_salt, 'password': hash}})
这里是采用email和salt确定文档,然后进行更新。
5.登陆验证
打开登陆页面,输入在dz登陆的帐号密码验证是否成功,若提示失败可能需要重启服务器。目前仅是帐号密码部分进行了迁移和修改,可能还会有部分尚未完成修改,等后续发现再改吧