從Discuz遷移帳號密碼到NodeBB

從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": "[email protected]",
    "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登陸的帳號密碼驗證是否成功,若提示失敗可能需要重啓服務器。目前僅是帳號密碼部分進行了遷移和修改,可能還會有部分尚未完成修改,等後續發現再改吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章