文章

独立寒秋,湘江北去,橘子洲头,看万山红遍,层林尽染;漫江碧透,百舸争流。

综述

转眼间已然九月,回首八月,虽多次有想记录些什么的冲动,然而不成文章,尽是些小Tip,独立开一章显得空,而若不记日后忘却又难免有些可惜,故做此番记录。
今天是996动员最后一天,虽不止这次大干50天的作用有没有达到领导的预期,从我还有时间来打这些文字来看,想来目标应是达成了。
闲言少叙,本篇文章记录的对象主要包括:

  • NodeJs登录功能中的加密实现。
  • 基于centos yum的mysql安装。
  • linux通过SSH来实现的文件,文件夹传输。
  • linux的定时任务。

基于Koa的登录实现

说到登录功能,可以说是Web项目中Hello World一般的存在,如果结合上注册以及用户管理功能,增删改查可以说就齐活了。能把这一套做下来,其它功能想必也不会做不出来。
今天我们单拿登录功能说事,也就是只看'查'这一项。首先,来看下基本流程:

  1. 前端点击登录->将用户密码加密像后台传输
  2. 后台解密用户密码,通过用户名去数据查询密码信息
  3. 对比查出来的密码和上传的密码返回结果
  4. 前端接受结果做出响应

想来怎么获取到用户输入,怎么像后台传输,以及怎么做出响应过于基本,再次不再赘述,单拿加密解密来说事。
加密有两部分,首先是前端像后台传输时的加密,其次是存入数据库时的加密,咋一看好像都是加密,但是这里面其实讲究不少,首先,比如前端像后台传输的加密,后台是需要解密的,也就是说它需要弄明白你发过去了什么。
但是存入数据库的加密就不一样了,它不需要把从数据库里取出来的值做解密,只需要判断这个值和前端传来的值是否一致就行了,也就是说从数据库里取出来的谜一般的字符串可以不用解密出来,但是,如果我把明文沿一定的顺序去加密一定会得到一样的迷之字符串。
如果说传输端的加密,我见过有项目用DES加密的,但是我发现它每次传进去同样的值会返回一样的值,这就带来一个问题,假如我被抓包了,它并不需要知道实际值是什么,直接传这个被加密后的DES加密的字符串给后台,一样能通过验证。
这种情况,其实可以考虑按一定规律拼个时间戳进去,后台判断比如10S内有效之类的,不过也只是想想,我没用这个方法因为我找到一个前端加密包,可以有更多的选择。

RSA非对称加密

RSA依赖大数分解,具体原理限于篇幅略过不表,使用来说RSA有一对密匙,一个公匙,一个私匙,用公匙加密的信息,可以用私匙来解密,且即使是同样的内容,公匙加密得到的字符串每次也是不一样的。
NodeJs内置的crypto库可以方便的进行RSA加密解密。前端的话有一个叫jsencrypt的库可以做RSA加密解密。下面附上个列子:

//前端
var publicKey = "-----BEGIN PUBLIC KEY----.........-----END PUBLIC KEY-----";
var jsencrypt = new JSEncrypt();
    jsencrypt.setPublicKey(publicKey);
var result = jsencrypt.encrypt(upDataStr);

publicKey是一个公匙,当然你也可以在每次登陆前先请求一次来获取,这里我选择了直接存在前端。这里加密的是字符串,可以把想上传的单个字段进行加密,或者直接转成json字符串进行加密。

//后端 nodeJs
const crypto = require('crypto');
var privateKey = '.....'; //略
var enData = ctx.request.body.data; //从前台获取到的加密字符串
var enBuffer = new Buffer(enData,"Base64");
var dataStr = crypto.privateDecrypt({key:privateKey,padding:crypto.constants.RSA_PKCS1_PADDING}, enBuffer).toString();

这里有个小坑,jsencrypt的加密方式和nodejs默认的加密方式并不一致,所以解密的时候需要指定 padding:crypto.constants.RSA_PKCS1_PADDING。
而且,解密前需要先转成基于Base64的Buffer。

sha512

上面提到了怎么在传输端进行加密,下面来讲讲往数据库存的时候怎么加密。
这里首先要提一个概念:salt就是"盐",简单来说就是对数据进行加密的时候传入无关的字符串加大解密时的难度。一般来说盐是随机生成的字符串,和密码存一块,验证的时候讲前台传上来的值再进行一次加盐加密然后判断与后台存的加盐加密后的字符串是否相等。
也就是说即使后台存的加密后的密码字符串没有办法还原成明文密码也不影响验证,同时即使被拖库也密码也不会立刻被泄露,真是美哉。
下面是简单的实现:

const crypt = require('crypto');
var salt = crypto.randomBytes(64).toString('Base64') //生成长度为64的随机base64字符串作为盐
var upValue = crypto.pbkdf2Sync(password,salt, 100000, 64, 'sha512').toString('base64'); //同步进行,基于sha512进行加盐加密
//upValue为加密后的字符串,100000 是迭代次数,次数越多越安全..但也更费时

小结

这里列举了简单的登录模块中的加密实现,虽然基础简单,不过各种感觉够用了,如果要实现完整的登录功能其实还需要设置cookie或者token之类的,作为登录状态判断各有利弊。
koa2的话token有一个jsonwebtoken,想使用cookie的话,可以用koa-session 将session存在cookie中就是了。

基于centos yum的mysql安装

曾几何时,安装mysql的时候我比较喜欢通过wget去下载tar包去解压,然后配置....
但是装了几次之后感觉实在太麻烦了,于是找了找通过yum来安装的方法,实际上,换成apt-get估计流程也差不多。这里只提yum。

# 权限问题  chown -R mysql:mysql /var/lib/mysql
# 下载mysql源安装包
wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
# 安装mysql源
yum localinstall mysql57-community-release-el7-8.noarch.rpm
# 检查mysql源是否安装成功
yum repolist enabled | grep "mysql.*-community.*"
# 安装
yum install mysql-community-server 
# 开启MySql服务
systemctl start mysqld
# 开机启动
systemctl enable mysqld
systemctl daemon-reload
# 获得默认密码 
grep 'temporary password' /var/log/mysqld.log
# 进入mysql修改密码
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass!'
# 修改root的访问来源
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'MyNewPass' WITH GRANT OPTION;
# 创建新用户
GRANT ALL PRIVILEGES ON *.* TO 'mysqluser'@'%' IDENTIFIED BY ' MyNewPass' WITH GRANT OPTION

FLUSH PRIVILEGES;
# 修改编码和端口
# /etc/my.cnf
# character_set_server=utf8
# init_connect='SET NAMES utf8'
# port=4000

没什么特别好提的,安装的时候逐条复制就是了。

linux 基于ssh的文件传输

# 下载文件
scp -P 4008  [email protected]:/download/1.jpg /download/1.jpg
# 从192.168.10.105 的/download/中 下载1.jpg 到本地的/download/ 并重命名为1.jpg

# 下载目录
scp -P 4008 -r [email protected]:/download /download
# 从192.168.10.105 中将/download/ 下载到本地 /download/

# 将文件上传
scp -P 4008  /download/1.jpg [email protected]:/download/1.jpg
# 从 本地的/download/中 上传 1.jpg 到192.168.10.105的/download/ 并重命名为1.jpg

# 将目录上传
scp -P 4008 -r /download [email protected]:/download
# 将 本地的/download/ 上传  到192.168.10.105的/download/
# 注意会在download中再建立一个download文件夹

scp命令基于ssh 如果目标机器没有开启ssh,那么一切都免谈...另外它不会做文件是否重复的验证,如果存在会直接覆盖掉。

linux的定时任务

在实际的使用中,经常会出现需要在指定的时间执行这一类的需求,要我现在来想,也就只能写个定时器,在指定的时间执行,或者隔一段时间轮训一次,判断时间是否差不多到了...
问题也很明显,不能保证一定准时执行,写个死循环,或者隔一秒轮询一次或许可以,但是效率未免太差了。
然而在linux中有一个现成的定时任务,就是crontab命令。

crontab -e # 进入编辑模式,第一次执行的时候会让你选择用什么编辑器
# 配置文件命令格式
minute hour day month week command
其中: minute: 表示分钟,可以是从0到59之间的任何整数。
hour:表示小时,可以是从0到23之间的任何整数。
day:表示日期,可以是从1到31之间的任何整数。
month:表示月份,可以是从1到12之间的任何整数。
week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。
command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。
在以上各个字段中,还可以使用以下特殊字符:
星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。
# 列子:
# 每6个小时输出一个hello World
* 6 * * * echo Helloworld
# 每星期六的 晚上11:00 重启smb
0 23 * * 6 /etc/init.d/smb restart
# 配置完后重启
service cron restart

/sbin/service crond start    //启动服务
/sbin/service crond stop     //关闭服务
/sbin/service crond restart  //重启服务
/sbin/service crond reload   //重新载入配置

service crond status //crond服务的状态
ntsysv //查看是否开机启动
chkconfig –level 35 crond on //加入开机启动

用法非常一目了然,也蛮方便的,虽然不知道怎么实现的,但肯定比写个死循环做判断要强....

结语

这一个月一方面沉迷工作,无法自拔,另一方面久违的感冒了,着实没有尝试各种新鲜事物的动力。
python也是看完基本语法就搁下了,借我《图解http》的那个人也不干了...每天除了工作就是有一搭没一搭的完善着爬虫,做做codewars,或者写一些自己需要的后台组件啥的。
但终归难登大雅之堂,脱离不了玩具的范畴。
扯远了,总归,不定时的总结下最近遇到的问题,或者小功能啥的,收获不能说没有,主要能确认下接下来的方向。
于我当前,也就是做完这些对我自身实用的小玩意后把他们提出来,单独作为一个项目。虽然,从项目组织这个角度来看,我当前的很多做法非常不合理,不过考虑到因为只是自己开发,自己用,倒也不是不能理解。
而且,虽然能感觉到不合理,但暂时却不知道怎么改合适,不免遗憾,总之先把功能做出来,优化的事情,以后再说吧,如果有以后的话....

Comment

This is just a placeholder img.