electron-本地存储实现自动登录(sqlite3)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

1.首次登录
创建本地数据库->创建表->将数据存到表中->数据写入结束后将数据库写入加密文件->删除数据库文件。
2.需要使用数据时
将加密的数据库文件进行解密->创建数据库连接->进行数据获取操作->操作结束后将数据库文件加密后放入加密文件->删除数据库文件。


一、安装sqlite3

npm install sqlite3

二、对sqlites的数据库操作进行封装

const sqlite3 = require('sqlite3').verbose();

let sqlite = {};
sqlite.db = null;

sqlite.open = (filePath, key) => {
    console.log('1 open', filePath);
    return new Promise((resolve, reject) => {
        sqlite.db = new sqlite3.Database(filePath, err => {
            if (err) {
                reject('Open error: ' + err.message)
            } else {
                resolve(filePath + ' opened');
            }
        })
    })
}

// any query: insert/delete/update
sqlite.run = query => {
    console.log('2 run', query);
    return new Promise((resolve, reject) => {
        sqlite.db.run(query, err => {
            if (err) reject(err.message);
            else resolve(true);
        })
    })
}

// first row read
sqlite.get = (query, params=[]) => {
    console.log('2 get', query);
    return new Promise((resolve, reject) => {
        sqlite.db.get(query, params, (err, row) => {
            if (err) reject('Read error: ' + err.message)
            else resolve(row);
        })
    })
}

// set of rows read
sqlite.all = (query, params = []) => {
    console.log('2 all',query);
    return new Promise((resolve) => {
        sqlite.db.all(query, params, (err, rows) => {
            let res;
            if (err) {
                res = {
                    type: 'err',
                    data: err
                };
            } else {
                res = {
                    type: 'rows',
                    data: rows
                };
            }
            resolve(res);
        })
    })
}

// set of rows read
sqlite.exec = query => {
    console.log('2 exec');
    return new Promise((resolve, reject) => {
        sqlite.db.exec(query, (err, rows) => {
            if (err) reject('Read error: ' + err.message)
            else resolve(rows);
        })
    })
}

// each row returned one by one
sqlite.each = (query, params, action) => {
    console.log('2 each',query);
    return new Promise((resolve, reject) => {
        sqlite.db.serialize(() => {
            sqlite.db.each(query, params, (err, row) => {
                if (err) reject('Read error: ' + err.message)
                else if (row) action(row);
            })
            sqlite.db.get('', (err, row) => {
                resolve(true);
            })
        })
    })
}

sqlite.close = (key) => {
    return new Promise((resolve, reject) => {
        sqlite.db.close();
        resolve(true);
    })
}

export default sqlite;

三、文件的加密、解密、读取、写入

const crypto = require('crypto');
const fs = require('fs');

/**
 * 加密参数
 * algorithm
 * password 加密密钥
 */
const algorithm = 'aes-128-ctr';
const password = '123456789abcdefg';
const iv = 'abcdefg123456789'


/**
 * 加密
 * @param buffer 待加密文本
 * @returns {Buffer} 加密之后文本
 */
export function Encrypt(buffer) {
  let cipher = crypto.createCipheriv(algorithm, password, iv)
  return Buffer.concat([cipher.update(buffer), cipher.final()]);
}

/**
 * 解密
 * @param buffer 待解密文本
 * @returns {Buffer} 解密之后文本
 */
export function Decrypt(buffer){
  let decipher = crypto.createDecipheriv(algorithm, password, iv)
  return Buffer.concat([decipher.update(buffer), decipher.final()]);
}

/**
 * 读取未加密文件
 * @param filePath 文件路径
 * @returns {Buffer} 数据流
 */
export function readPlaintextDatabaseFile(filePath) {
  return fs.readFileSync(filePath);
}

/**
 * 读取加密文件
 * @param filePath 文件路径
 * @returns {Buffer} 数据流
 */
export function readCiphertextDatabaseFile(filePath) {
  let dataFlow = fs.readFileSync(filePath);
  return Decrypt(dataFlow);
}

/**
 * 明文写入数据
 * @param filePath 路径
 * @param data 待写入数据
 */
export function writePlaintextDatabaseFile(filePath, data) {
  fs.writeFileSync(filePath, data);
}

/**
 * 加密写入文件
 * @param filePath 路径
 * @param data 待写入数据
 */
export function writeCiphertextDatabaseFile(filePath, data) {
  fs.writeFileSync(filePath, Encrypt(data));
}

/**
 * 删除文件
 * @param filePath 待删除文件路径
 * @returns {Promise<Object>} 返回结果
 */
export function deleteFile(filePath) {
  fs.unlinkSync(filePath);
}

四、数据库文件不存在时

a.判断数据库文件存在没

/**
 * 判断 loginUsers 文件是否存在
 * 否则创建 loginUsers 文件
 * 返回参数 0:代表已经创建过数据表 1:代表没有创建过需要创建
 * @return {Promise<unknown>}
 */
export function creatLoginUsersPort() {
    return new Promise(resolve => {
        try {
            fs.readFileSync(loginUserFilePath);
            resolve({code: 200, message: 'loginUsers读取成功',type:0});
        } catch (e) {
            fs.writeFileSync(loginUserFilePath, '');
            resolve({code: 200, message: 'loginUsers创建成功',type:1});
        }
    })
}

b.不存在就创建本地数据库并创建表

/**
 * 创建本地登录用户数据库
 * @returns {Promise<unknown>}
 */
export async function creatLoginUserTablePort() {
    // 打开数据库
    await sqlite.open(loginUserDbPath, getKey());
    // 执行SQL
    await sqlite.run(createLoginUserColumnsTable());
    await deleteDb();
}
/**
 * 创建登录用户信息表
 * @returns {string}
 */
export function createLoginUserColumnsTable() {
    return `CREATE TABLE IF NOT EXISTS T_LOGIN_USER (
        contact_id_ TEXT PRIMARY KEY,
        ent_id_ TEXT,
        ent_name_ TEXT,
        username_ TEXT,
        password_ TEXT,
        ent_version_ TEXT,
        update_time TEXT,
        auto_login_ Long,
        mindful_password_ Long
  )`
}

c.当用户输入账号密码进行登录后将数据写入数据库

/**
* 登录
*/
function login(){
  //判断用户是否存有过数据,存过就更新数据,没存就写入数据
  this.selectUserInTable().then(async res => {
    //更新数据
    console.log('--------------更新数据');
    this.userInfo.contactId = res.contactId;
    await updateLoginUserData(this.userInfo);
  }).catch(async() => {
    //写入数据
    console.log('--------------写入数据');
    let contactId = this.uuid2();
    this.userInfo.contactId = contactId;
    await insertLoginUserDataPort(this.userInfo);
  });
}
/**
 * 读取加密文件并创建数据库文件
 * 写入数据打开数据库连接
 */
async function creationDb(){
    // 读取加密文件并解密数据
    let dbData= await readCiphertextDatabaseFile(loginUserFilePath);
    // 将解密数据写入数据库文件
    await writePlaintextDatabaseFile(loginUserDbPath, dbData);
    // 生成并打开数据库
    await sqlite.open(loginUserDbPath,  getKey());
}

/**
 * 将数据库数据加密写入指定文件并删除数据库文件
 */
async function deleteDb(){
    // 关闭连接
    await sqlite.close(getKey());
    //读取数据表数据
    let data = readPlaintextDatabaseFile(loginUserDbPath);
    //将数据表数据加密写入文件
    await writeCiphertextDatabaseFile(loginUserFilePath,data);
    // 删除数据库文件
    await deleteFile(loginUserDbPath);
}
/**
 * 写入登录用户数据
 */
export function insertLoginUserDataPort(userInfo) {
    return new Promise(async (resolve, reject) => {
        await creationDb();
        const r = await sqlite.run(getLoginUserDataTable(userInfo));
        await deleteDb();
        if (r) {
            resolve(r);
        } else {
            reject(0);
        }
    })
}
/**
 * 登录用户更新/写入
 * @param e
 * @returns {string}
 */
export function getLoginUserDataTable(e) {
    return `INSERT OR REPLACE INTO T_LOGIN_USER VALUES(
     "${e.contactId}",
     "${e.entId}",
     "${e.entName}",
     "${e.username}",
     "${e.password}",
     ${e.entVersion},
     "${e.updateTime}",
     ${e.autoLogin},
     ${e.mindfulPassword}
    )`;
}

五、数据库文件存在时

/**
* 读取本地数据库文件,查看是否已有保存的账号密码
*/
readLocalFile() {
  //获取用户信息
  getLoginUserDataPort().then(data=>{
    console.log(data,'-----------');
    if (data && data.length !== 0) {
      //判断是否自动登录
      if(data[0].autoLogin === 1){
        this.form.username = data[0].username;
        this.form.password = data[0].password;
        this.entId = data[0].entId;
        this.userInfo = data[0];
        const formData = {
          username: this.form.username,
          password: this.form.password,
          loginType: "0",
        };
        getTokenApi(formData).then(res=>{
          if (res.code == "200") {
            this.token = res.data.token;
            this.refreshToken = res.data.refreshToken;
            this.chooseEnt();
          }else{
            this.$message.warning(res.msg);
          }
        })
      }else if(data[0].mindfulPassword === 1){
        this.form.password = data[0].password;
        this.savePwd = true;
        this.isPasswordEncrypt = false;
      }
    } else {
      console.log("读取自动登录数据失败");
    }
  });
}
/**
 * 查询本地已保存登录用户
 * @returns {Promise<unknown>}
 */
export async function getLoginUserDataPort() {
    await creationDb();
    let dataInfo;
    await sqlite.all(selectLoginUserData()).then((res)=>{
        if(res.type === 'err'){
            dataInfo = [];
        }else{
            dataInfo = res.data;
        }
    });
    await sqlite.close(getKey());
    // 删除数据库文件
    await deleteFile(loginUserDbPath);
    return new Promise((resolve, reject) => {
        resolve(dataInfo);
    })
}
/**
 * 查询本地登录用户列表
 * @returns {string}
 */
export function selectLoginUserData() {
  return `select contact_id_ as contactId,
    username_ as username,
    password_ as password,
    ent_id_ as entId,
    ent_name_ as entName,
    ent_version_ as entVersion,
    update_time as updateTime,
    auto_login_ as autoLogin,
    mindful_password_ as mindfulPassword from T_LOGIN_USER order by update_time desc`;
}
  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值