[Flarum] 利用Old Passwords扩展

将旧网站用户密码密文迁移至Flarum – 以Wecenter举例

!!!文章内容涉及数据库操作,请在操作前备份网站数据库和文件,并严格按照文章内容指示操作,如未遵循,概不负责!!!

之前做FMA社区的时候,用了一个并不是很常见的架构Wecenter作为底层进行二次开发,如今多年过去,Wecenter社区已经不再活跃,开发者也都跑了大半,多半是寄了,再用下去沉没成本太高,因此考虑更换底层架构,全面升级至流行的Flarum

但网站换架构谈何容易,这里头涉及到多种数据类型转换的问题,比如文章的迁移,再比如很让人头疼的密码迁移

这篇文章就记录了我如何利用Flarum的一个扩展,迁移Wecenter数据库中用户密码的故事

首先,密码迁移需要知道这样几个值

  1. 获知密码的明文或者密文(这是当然,这就是密码本体,没有它怎么进行转换呢?)
  2. 获知密码的加密方式(查阅资料,或是通过正向加密比对得知加密算法)
  3. 如果密码“带盐”,还需要知道“盐值”

(拓展阅读:什么是“带盐”?《MD5加密 + 加盐》 博客园 – HP.Liu的文章

以Wecenter举例,Wecenter存放用户信息的数据表长这个样子:

其中password存放的是密码经过加密后的密文,salt则是随机生成的盐值

那么加密算法我们怎么获取呢?这里通过正向加密比对获得——比方说我知道我自己的一串密码,且Wecenter的数据库里也存放了我的密码经由Wecenter加密后的密文,那我就可以通过输入我的密码和盐值,并比对加密结果得知Wecenter的加密方式,这里使用的工具是cmd5这个网站:CMD5在线加密

得知经过比对后的加密算法是MD5两次加密(末尾加盐)——

接下来就请出我们的Flarum扩展:Old Passwords

使用部分是这样说的(机翻)——

解释一下就是这个插件需要

  1. 登录Flarum后台启用插件
  2. 启用插件后,users表会多一列migratetoflarum_old_password,用于键入JSON序列化后的旧密码(具体方式下文讲解),不输入的时候为null
  3. 一旦migratetoflarum_old_password中输入的内容符合JSON序列化的格式,系统会自动对未来某一时刻升级后的Flarun网站,在用户尝试用旧架构(如Wecenter)的密码登录时,对密码进行加密,并与migratetoflarum_old_password中的密文比对,如果比对成功,将会以Flarum加密密码的方式(Bcrypt)覆盖掉Flarum数据库中password

有关于JSON序列化的格式,这里就拿Wecenter的加密方式举例:

因此我们需要的格式是:

{"type":"md5-double-bcrypt","password":"[wecenter数据库users表中password]","salt-after":"[wecenter数据库users表中salt"]}

由此我们设计一个专门读取wecenter数据库的python文件,将password字段和salt字段作为变量,传入migratetoflarum_old_password,方可为Flarum数据库添加对应用户的密码(无需知晓明文)

这里给出一段代码作为参考,其中将Wordpress的users表以csv文件的形式导出(分隔符为','即英文逗号,含表头),存放在python脚本同目录下的index文件夹内以便读取:

import csv
import time

def format_date(timestamp):
    timestr = str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(timestamp))))
    return timestr

sql_header = 'INSERT INTO `users` (`id`, `username`, `email`, `is_email_confirmed`, `password`, `avatar_url`, `preferences`, `joined_at`, `last_seen_at`, `marked_all_as_read_at`, `read_notifications_at`, `discussion_count`, `comment_count`, `read_flags_at`, `suspended_until`, `suspend_reason`, `suspend_message`, `migratetoflarum_old_password`) VALUES\n' # 定义表头
sql_file = open('export.sql', 'w+')
sql_content = ''
index_from = 1 # uid从几开始排序

source_table = csv.reader(open('input/aws_users.csv','r'))
total_lines = len(open('input/aws_users.csv').readlines())
for row in source_table:
    if source_table.line_num == 1:
        for i in range(0, len(row)):
            # 打印表头
            print(i, row[i])
    else:
        line_end_symbol = ','
        if source_table.line_num == total_lines:
            line_end_symbol = ';'
        # 把想要的元素挑出来
        temp_list = [
            str(int(row[0]) + index_from), # id
            row[1].join(["'","'"]), # 用户名
            row[2].join(["'","'"]), # 邮箱
            '0', # 是否已验证邮箱
            '$2a$10$j86jd7dAg6HMGm7rxFEiv.IYzx5IrNv2nVbXKaAh3.EevQhFhcdFW'.join(["'","'"]), # 默认密码(通过'flarum#123'字符串Bcrypt加密生成)
            'NULL', # 头像
            'NULL', # 偏好
            format_date(row[12]).join(["'","'"]), # 注册时间
            format_date(row[17]).join(["'","'"]), # 上次活跃时间
            'NULL', # marked_all_as_read_at
            'NULL', # read_notifications_at
            '0', # 发帖数
            '0', # 评论数
            'NULL', # read_flags_at
            'NULL', # suspended_until
            'NULL', # suspend_reason
            'NULL', # suspend_message
            ('{"type":"md5-double","password":"' + row[4] + '"' + ',"salt-after":"' + row[5] + '"}').join(["'","'"]) # migratetoflarum_old_password
        ]
        sql_content = sql_content + '(' + ', '.join(temp_list) + ')' + line_end_symbol + '\n'
print(sql_content)

sql_file.write(sql_header + sql_content)
sql_file.close()

运行此python脚本,用于导入数据库的sql文件便会生成为脚本同目录下的export.sql文件,再利用PhpMyAdmin一类的工具导入Flarum数据库即可

发表评论

邮箱地址不会被公开。