MySQL导入csv文件导出sql文件

首先创建数据库

1
2
create database covid_19;
use covid_19;

使用数据库,并且创建一个表

这里表的格式比较随意

1
2
3
4
5
6
7
CREATE TABLE counties (
date VARCHAR(20) NULL,
county VARCHAR(40) NULL,
state VARCHAR(40) NULL,
cases INT NULL,
deaths INT NULL
);

使用如下命令加载csv文件到指定的表中

注意替换文件路径。另外,这里忽略掉了csv中第一行的数据。

1
2
3
4
5
6
LOAD DATA
INFILE 'D:\\Learning\\DataAnalysis\\covid-19-prediction\\data\\counties.csv'
INTO TABLE counties
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
IGNORE 1 ROWS;

导出数据库

在shell窗口或者cmd窗口,使用如下命令,即可导出指定的数据库。

注意,这里导出文件名应该是绝对路径。

如果使用window系统,注意不要使用power shell!!否则导出的sql文件可能无法使用!

1
mysqldump -u [用户名] -p [数据库名] > [导出的文件名]

使用js和后端模糊查询实现搜索提示功能

背景:

最近毕节市煤矿预警平台第一阶段完成了,趁着这段时间记录一下前面学习的东西。这次记录的是,根据用户的输入,匹配煤矿名称候选项的功能实现。前端用的技术有jquerybootstrap4vuehtml自带的datelist标签,后端的技术有mybatis(其实后端没干啥就是做了一个模糊查找)。


实现的逻辑:

  1. 当用户在输入框输入东西的时候,前端将输入框的内容发送给后端(这里用的是ajaxget请求)

  2. 后端根据用户输入和当前页面的县区(考虑到后端查询的效率,先将查询的范围缩小到某一个县区)进行模糊查找,查询结果返回前端

  3. 前端接受到后端的查询结果,将结果保存到vue组件的对应属性里面

  4. 使用vue-for循环,在前端的datalist标签里面输入返回结果,供用户选择


前端实现:

由上面的逻辑可见,前端需要响应用户输入,发送ajax请求,vue-for循环,这里一步一步来。

首先,相应用户输入。这里直接用htmlinput标签自带的oninput属性即可响应用户输入

1
2
3
4
5
<input id="coalMineName" type="text" class="form-control" list="coalMineNames"
oninput="searchCoalMineName($('#coalMineName').val())">
<datalist id="coalMineNames">
<option v-for="n in coalMineNames" v-bind:value="n">
</datalist>

当input输入框检测到输入就将输入框中的内容传递给一个searchCoalMineName函数。注意到这里由一个vue-for循环是用来显示查询结果的,后面再进行说明

control.js中编写searchCoalMineName函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function searchCoalMineName(searchText) {
$.ajax({
type: 'GET',
dataType: 'JSON',
url: '/table/mine/find/coalMineName',
data: {
'province': getUrlParameter('province'),
'searchText': searchText
},
success: function (data) {
inputInVue.coalMineNames = data;
},
error: function (xhr, type, errorThrown) {
}
})
}

这里的getUrlParameter函数是提取url中的参数,这里提取的就是县区名称,该函数的代码可以参照Stake Overflow这里不详细展开

searchText就是输入框的内容,通过jquery框架发送ajax请求到后端。将接收到的查询结果传递到vue容器的coalMineNames属性中

vue容器会检测到容器的相关属性发生了变化,会自动更新模板的相关内容,比如上面的vue-for循环就会因为返回的查询结果的变化,开始自动更新datalist标签中的option,最后根据浏览器的实现,就会渲染成一个下来列表,不同浏览器的实现不同可能会有bug(貌似搜狗浏览器就出现了问题)


后端实现:

这里使用了SpringBoot框架,所以先用一个Controller接收请求

1
2
3
4
5
6
7
8
9
@GetMapping("/find/coalMineName")
public List<String> findCoalMineName(@RequestParam String province, @RequestParam String searchText) {
if (!province.equals("")) {
if (province.equals("合计"))
province = "%%";
return coalMineMapper.findCoalMineNameByInput("%" + searchText + "%", province);
}
return new ArrayList<>();
}

注意到,对于合计字段不应该再限制县区名称,而是应该再所有县区之间搜索符合条件的煤矿名称,这里对县区名称也可以用一个模糊查询,当县区名称为‘合计’的时候,只要用”%%“正则表达式就可以查询所有的县区煤矿名称了

sql语句中使用LIKE关键字配合正则表达式”%查询条件%“,允许查询条件前后出现若干个字符,以此实现模糊查询。mybatis代码如下:

1
2
@Select("SELECT CoalMineName FROM tbCoalMine WHERE CoalMineName LIKE #{searchText} AND Province LIKE #{province}")
List<String> findCoalMineNameByInput(@Param("searchText") String searchText, @Param("province") String province);

由此即可根据用户输入进行模糊查询,返回候选结果


以上~

使用Docker部署jar包

背景

最近在用springBoot写毕节市煤矿预警的项目,上线之后又面临着多次修改,而且在实际部署到毕节市之前还要先部署到自己的服务器给老师先看看,挺麻烦的。每次部署都在在搜索引擎找小白教程,虽然来来去去去就那基本命令,但是不是每天都写确实进不了脑子,这里索性直接记下来。


删除原来的镜像和容器

部署项目之前需要将原来运行的docker容器给关掉,容器开着一来占用服务器资源,二来占用了原来的端口(为了安全服务器防火墙是一个项目开一个端口)。下面直接贴上经常使用的docker相关命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
查看所有容器ID
docker ps -a

停止指定的容器
docker stop [容器id]

删除指定的容器
docker rm [容器id]

查看所有image
docker imaged

删除docker镜像
docker rmi [镜像ID]

部署jar包

删除了原来的容器和镜像之后,开始部署jar包。首先,将jar包放在某个项目目录里面,然后再目录内新建一个Dockerfile文件,后面docker就是根据这个文件的内容生成镜像的。

Dockerfile文件内容参考如下

1
2
3
4
5
FROM java:8
MAINTAINER miaopashi
ADD demo-0.0.1-SNAPSHOT.jar demo.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","demo.jar"]

构建docker镜像

1
docker build -t my/demo .

运行容器

1
docker run -d --restart=always --name demo -p 8080:8080  my/demo

说明:restart选项的内容表示docker容器在服务器开机之后会自动重启


以上~

毕节市可视化Java项目博客记录----日期格式的转换

数据可视化中经常要使用日期作为查询条件或者展示内容,这需要前后端对时间进行转化,本篇的目的是记录我在本项目中使用的日期转换方法


背景

后端虽然可以直接使用固定格式的字符串(如:”2021-12-12 11:11:11”)进行sql查询,但是为了保证时间的准确性(排除诸如不同时区对时间的影响),最好还是使用Date类型进行查询
另一方面,前端显示的时间格式一般为字符串(如:”2021-12-12 11:11:11”或”2021-12-12T11:11:11”,前者作为前端表格显示的时间结果并且可以直接作为sql查询条件,后者用于h5自带的datetime类型Input标签的时间显示
这就导致后端需要对时间字符串Date类型变量进行转换,或者也可以把转换工作交给前端。在这个项目中,对于空格时间字符串后端转化成Date类型,对于T时间字符串则先在前端将其转化为空格时间字符串,后续会进行说明

顺便在后面可以讲一下,如何在浏览器使用一个h5新组件,实现日历框输入。但是这个组件目前在部分主流浏览器比如火狐浏览器是不支持的(所幸谷歌浏览器是支持的),后期考虑使用其他框架的日历输入框。


Java中日期的格式化

Java中的日期格式化可以通过DateFormat类和SimpleDateFormat完成,后者可以指定相对随意的文本格式,所以这里使用后者进行日期格式转换

可以看到SimpleDateFormat构造方法的参数可以比较方便地指定时间字符串的样式,其中y表示面年份、M表示月份、d表示天数……
http://c.biancheng.net/view/878.html
需要注意的一点是,由于参数规定了特殊字符对应具体的时间概念,所以会和时间字符串中的非时间字符产生歧义。比如:对于”2021-12-12T11:11:11”,如果想利用SimpleDateFormat转化为Date变量,调用构造方法SimpleDateFormat("yyyy-MM-ddTHH:mm:ss"),参数中的T会产生协议,当调用parse()方法的时候就会报错。这就是我在项目中把T时间字符串和空白字符串之间的转换留在前端的原因。

1
2
3
4
5
6
7
// 使用SimpleDateFormat需要先生成一个对象
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 调用这个对象的parse方法,可以根据空格时间字符串,生成Date变量
Date startDate = f.parse(startTime);
// 调用这个对象的format方法,可以根据Date变量,生成指定格式的字符串
SimpleDateFormat nf = new SimpleDateFormat("今天是yy-MM-dd");
String today = nf.format(new Date());

可以看到SimpleDateFormat()构造方法的参数可以比较方便地指定时间字符串的样式,其中y表示面年份、M表示月份、d表示天数……

字母 含义 示例
y 年份。一般用 yy 表示两位年份,yyyy 表示 4 位年份 使用 yy 表示的年扮,如 11; 使用 yyyy 表示的年份,如 2011
M 月份。一般用 MM 表示月份,如果使用 MMM,则会 根据语言环境显示不同语言的月份 使用 MM 表示的月份,如 05; 使用 MMM 表示月份,在 Locale.CHINA 语言环境下,如“十月”;在 Locale.US 语言环境下,如 Oct
d 月份中的天数。一般用 dd 表示天数 使用 dd 表示的天数,如 10
D 年份中的天数。表示当天是当年的第几天, 用 D 表示 使用 D 表示的年份中的天数,如 295
E 星期几。用 E 表示,会根据语言环境的不同, 显示不 同语言的星期几 使用 E 表示星期几,在 Locale.CHINA 语 言环境下,如“星期四”;在 Locale.US 语 言环境下,如 Thu
H 一天中的小时数(0~23)。一般用 HH 表示小时数 使用 HH 表示的小时数,如 18
h 一天中的小时数(1~12)。一般使用 hh 表示小时数 使用 hh 表示的小时数,如 10 (注意 10 有 可能是 10 点,也可能是 22 点)
m 分钟数。一般使用 mm 表示分钟数 使用 mm 表示的分钟数,如 29
s 秒数。一般使用 ss 表示秒数 使用 ss 表示的秒数,如 38
S 毫秒数。一般使用 SSS 表示毫秒数 使用 SSS 表示的毫秒数,如 156

表格来自:http://c.biancheng.net/view/878.html
需要注意的一点是,由于参数规定了特殊字符对应具体的时间概念,所以会和时间字符串中的非时间字符产生歧义。比如:对于”2021-12-12T11:11:11”,如果想利用SimpleDateFormat转化为Date变量,调用构造方法SimpleDateFormat("yyyy-MM-ddTHH:mm:ss"),参数中的“T”会产生歧义,当调用parse()方法的时候就会报错。这就是我在项目中把T时间字符串空白字符串之间的转换,留在前端的原因。


JavaScript中的字符串格式化

在上面遇到了T时间字符串的转化问题,这里选择了在前端把T字符串转为空格字符串,后端再由空格字符串转为Date变量,或者直接进行sql查询。下面贴上前端的字符串转化的代码

通过指定oldSignnewSign,可以实现T字符串和空格字符串的转化(如T转空格则调用getDateTimeString(originString, 'T', ' ')),当然这个代码是临时拼凑的所以写的不咋滴

1
2
3
4
5
6
7
8
9
10
let getDateTimeString = function getDateTimeString(originString, oldSign, newSign) {
// 在2021-11-11T00:00:00与2021-11-11 00:00:00之间相互转化
let timeValues = originString.split(oldSign),
res = timeValues[0] + newSign + timeValues[1];
if (res !== " undefined") {
return res;
} else {
return "";
}
}

通过指定oldSignnewSign,可以实现T字符串和空格字符串的转化(如T转空格则调用getDateTimeString(originString, 'T', ' ')),当然这个代码是临时拼凑的所以写的不咋滴


使用html<input type="datetime-local">标签实现日历框输入

在html5中可以指定input标签的type为datatime-local,使得input输入框使用--年--月--日 xx:xx:xx的日期格式,以日历框的形式进行日历输入。

但是这个特性在部分浏览器,比如火狐浏览器,是没有实现的。所幸谷歌浏览器对这个特性有一个比较好看的实现,考虑到谷歌浏览器的使用率比较高,最后还是选择了这个组件。

有点奇怪的是,火狐浏览器的项目基金会mozilla对这个html特性进行了非常详细的介绍,尽管火狐浏览器并不支持它😂

1
2
3
4
5
6
7
8
<div class="col">
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text" for="startTime">开始时间</label>
</div>
<input class="form-control" id="startTime" type="datetime-local" step="01" value=""/>
</div>
</div>

需要注意的是,这里的value格式要遵循年/月/日Txx:xx:xx的格式,否则value值会失效。另外这里为了显示效果,使用了bootstrap4进行部分装点,核心的datetime还是html5的组件


以上~

工作室技术分享会

基础知识:

html、css、js的基本概念,可以参照w3school学习使用方法

echarts简介:

使用 JavaScript 实现的开源可视化库

提供常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭

详见echarts的官方文档

简单上手绘制一个饼图页面:

框架:flask(后端)、echarts(前端)

IDE:Pycharm

上手步骤:

  1. 下载echarts:从github下载编译产物
  2. 创建一个dom容器 id
  3. echarts的使用步骤(大象冰箱):
    1. 初始化echart(init)—-打开冰箱
    2. 编写option —-把大象推进去
    3. 导入option到echarts对象(setOption) —-关上冰箱
  4. 饼图的option使用了哪些配置(结合文档)

制作一个简单的大屏页面:

目标:

六个图的大屏(饼图、柱状图、地图、折线图、条形图、折线图)

制作步骤:

  1. 简单设计大屏,编写html中6个dom和css(记得引用)

  2. 新建js文件(Why?),结合实例或文档编写echarts代码,引用js到html

  3. 根据需求细化可视化组件的内容(颜色标题等)

关于地图可视化(地理坐标系):

  1. 详见echarts中option的geo配置
  2. 推荐阿里的地图选择器下载Json
  3. 在echarts中通过registerMap方法注册地图
  4. 地图标点需要用到经纬度,实际业务中有时只有目标的地址,可以使用百度地图的api将地址转换为经纬度
  5. series中指定type为map,绘制功能更丰富的地图可视化组件

讲讲echarts的其它相关操作:

  1. 事件响应(响应鼠标点击事件)

  2. dom容器的隐藏与显示(可以实现类似弹出框的效果)

  3. 数据异步加载(ajax)

阿里云《Serverless云开发从入门到实战》学习笔记

最近想学习一下项目部署的主流方式,比如Docker和Serverless。

前几天了解了一下Docker的基本概念和常用命令,能够把项目在服务器跑起来了。

所以现在计划了解一下Serverless,目标是使用Serverless部署之前写的小项目。

参考的文档是阿里云《Serverless云开发从入门到实战》


Serverless是一种构建和管理微服务架构的完整服务流程。是PaaS向Baas(后端即服务)和Faas(函数即服务)更小粒度的发展。它在无状态计算容器中运行,克重让使用者值关注自己的业务逻辑。如今微服务后端开发日益兴起,前端开始向全栈式开发转变,甚至出现了BFF(Backend For Frontend)中台架构层。而使用Serverless技术,可以将后端代码快速、高效地部署,并且不需要再进行服务器管理,不仅省去了运维的成本,还为前端调用服务提供了更加便捷的接口。下Serverle架构下,使用者通过云平台进行开发,服务商会提供便利的部署服务,根据应用的访问情况自动完整项目服务器的漂移以及扩容。


\


使用DNS映射解决Github访问缓慢的问题

最近访问Github的频率有点多,越来越发觉国内访问Github的速度太感人了,于是开始寻找解决方案。

然后在Github上看到了一个解决这个问题的项目

这项目会不定时地更新github的dns映射,只需要在需要访问github的时候,更新一下hosts文件,就可以利用dns映射,快速访问到github上的项目。

关于更新hosts文件,如果是手动更新,显然是难以接受的,于是该项目推荐了一个自动化更改hosts文件的软件,叫Switchhosts。

关于SwitchHosts的安装下载可以参照这里

一开始是想使用scoop安装的,发现scoop安装不太好用(有可能是网路问题),所以就没继续搞下去了。

作者直接提供了一个可执行版本,可以直接在windows系统安装。这里我就直接安装了。

安装完成之后,可以添加一个hosts。

在新的hosts文件中,设置Type为remote,设置相应的url(该项目在码云上更新的dns节点代码),更新间隔建议一个小时。打开软件挂在后台就可以了。

解决无法使用Pycharm自带的pip安装第三方库的问题

上次写可视化作业的时候,用pycharm出现了一个问题:无法直接使用IDE的setting中的pip安装第三方库。

几经周折之下,在Stack Overflow上找到了解答。

只要在新建项目的时候添加一个设定就可以了!


解决方法:

使用Pycharm,点击New Project,选择Pure Python(使用新建flask项目和Django项目的时候,我没有遇到上述的问题),勾选inherit global-site packges,新建项目即可~


由于Pycharm新建Pure Python项目的时候,是默认只使用本地的包的,所以当IDE使用pip命令下载第三方库的时候,系统会报错。只能直接只用终端的pip命令,才能够正常安装包。

勾选inherit选项能够允许IDE继承全局的第三方库,即Pycharm能够帮用户安装包,问题得到解决。

参考文章

使用Python可视化全国各省(除湖北)新冠疫情累计治愈病例数据

这周要完成大数据可视化的第一次作业,使用python实现最近很火的条形图竞赛效果。

上知乎参考了一下已有的代码,结合自己的需求,修改了一下。

在github上找到了大佬整理丁香园的新冠疫情数据,直接fork下来了。


需要解决的问题:

  1. 根据给定数据的属性(如不同的省份)类别,生成对应的颜色方案:

    1. 我的思路是导出目标属性列,使用set集合去重,获得颜色方案的数目
    2. 使用pyplot.cm.get_cmap()方法,根据需要的配色方案,生成随机颜色
    3. 把颜色和属性值映射到一个字典上,方便后续绘图调用
    4. 除了这种方案,还可以生成随机数转十六进制,获取RBG颜色方案,详细见被注释起来的代码
  2. 获得具体日期序列

    1. 由于收集数据的dateId是整型数据,不能直接用range()生成序列(否则会出现20200166这种不存在的日期)
    2. 可以使用datetime标准库生成某段日期之间的时间序列,指定数据中的dateId
    3. 在绘图的时候,直接打印dateId的效果不太好,绘图是应该在把dateId转换为xxx年xx月xx日的中文格式
  3. 关于可视化图的实现

    1. 可以参照具体的代码,这一部分主要是参照其它大佬的
    2. 使用matplotlib的animation库多次调用绘图函数,根据不同的日期绘制动图的某一帧
    3. 关于动图帧,就是根据累计治愈人数把筛选出来的数据排序,再根据省份名把颜色对应上去绘制条形图
    4. 当然除了绘制条形图还要绘制个各种标签,具体实现这里不展开

效果图:

由于目前域名还没有备案,图床暂时挂了,等元旦域名备案之后,就把图片补上来!


具体的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import random

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from datetime import datetime


def draw_barchart(dateId):
# 截取某一天的数据,并且使用value排序,保留前十项数据,用于绘制
dff = df[df['dateId'].eq(dateId)].sort_values(by='curedCount', ascending=True).tail(10)
ax.clear() # 清空上次绘制的图像
# 根据不同城市的名字,配置不同的颜色,绘制条形图
ax.barh(dff['provinceShortName'], dff['curedCount'], color=[color_dic.get(x) for x in dff['provinceShortName']])
# 绘制每行的标签和属性值文本
dx = dff['curedCount'].max() / 200 # 规定每个标签文本和条形终点的间隔
for i, (curedCount, provinceShortName) in enumerate(zip(dff['curedCount'], dff['provinceShortName'])):
ax.text(curedCount - dx, i, provinceShortName, size=14, weight=600, ha='right', va='bottom') # 绘制省份名
ax.text(curedCount + dx, i, f'{curedCount:,.0f}', size=14, ha='left', va='center') # 绘制属性值
# 配置整体的显示效果
dateStr = str(dateId)
date_str_fmt = "{0}年{1}月{2}日".format(dateStr[:4], dateStr[4:6], dateStr[6:]) # 把日期id转换为中文格式
ax.text(1, 0.2, date_str_fmt, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800) # 绘制日期id
ax.text(0, 1.06, '累计治愈人数(单位:人)', transform=ax.transAxes, size=12, color='#777777') # 绘制标签单位注解
ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
ax.xaxis.set_ticks_position('top')
ax.tick_params(axis='x', colors='#777777', labelsize=12)
ax.set_yticks([])
ax.margins(0, 0.01)
ax.grid(which='major', axis='x', linestyle='-')
ax.set_axisbelow(True)
ax.text(0, 1.10, '2020年1月31日到7月2日全国(除湖北省外)各省份及地区累计新冠治愈病例可视化图',
transform=ax.transAxes, size=24, weight=600, ha='left')
plt.box(False)


def datelist(beginDate, endDate):
# beginDate, endDate是形如‘20160601’的整形列表
date_l=[datetime.strftime(x,'%Y%m%d') for x in list(pd.date_range(start=beginDate, end=endDate))]
date_set = list()
for x in date_l:
date_set.append(int(x))
return date_set


if __name__ == '__main__':
mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认中文字体

data_route = 'china_provincedata_without_HB.csv' # 载入疫情数据,根据累计治愈,日期和省份缩写筛选三列信息
df = pd.read_csv(data_route, usecols=['curedCount', 'dateId', 'provinceShortName'])

pvc_list = list(set(df['provinceShortName'])) # 获取省份列表
pvc_num = len(pvc_list)
cmap = plt.cm.get_cmap("hsv", pvc_num + 1) # 随机生成省份数目对应的配色方案
# 生成配色方案字典 如:{'广东': (1.0, 0.0, 0.0, 1.0)}
color_dic = dict()
for i in range(pvc_num):
# rc = lambda: random.randint(0, 255)
# color_dic.update({pvc_list[i]: ('#%02X%02X%02X' % (rc(), rc(), rc()))})
color_dic.update({pvc_list[i]: cmap(i)})

fig, ax = plt.subplots(figsize=(15, 8)) # 指定生成图的尺寸

date_set = datelist('2020/1/31', '2020/07/02')
animator = animation.FuncAnimation(fig, draw_barchart, frames=date_set) # 生成动画
animator.save('新冠疫情累计治愈数据可视化.gif') # 保存gif

关于Spring Security文档上密码发展史的阅读报告

这周做实验,服务器宕机了

刚好闲着无聊,有机会看一下security的文档

突然看到一段密码存储的发展史

个人觉得挺有意思的,记录一下



简单翻译记录一下:

一开始用于用户认证的密码,是直接以文本形式存储在服务器的。

也就是说,用户的密码没有经过任何加密就直接存储在服务器的。

在这种情况下,有的黑客使用SQL inject等技术,攻击服务器,直接穷举出用户的密码。

然后利用窃取的密码,查看用户持有的数据!

为了应对这种情况,有开发者使用了哈希函数进行加密

将用户的密码进行一次哈希加密,再存储到数据库当中

这样,即便黑客通过服务器数据库穷举到了用户密码对应的哈希值,还是很难知道哈希值对应的用户密码

因此,用户密码的安全性暂时得以保障。


可是,道高一尺魔高一丈,黑客们又开始想到了Rainbow Table技术

黑客长时间穷举用户密码,并且把穷举像存储到一个彩虹表中,然后一次性攻击窃取密码

为了应对RainbowTable,开发者们开始使用“腌制过的密码”存储用户密码。

腌制过的密码是指,加入了salt的密码

salt是每个用户特有的一串字符

服务器存储的密码,通过salt和用户密码文本进行混合哈希运算,得到哈希值

通过这种技术,加大了黑客穷举密码的难度~


但是,随着计算机硬件的不断发展。

我们知道,现在的机器已经可以快速穷举256位的字符串来穷举密码了,所以”Salted Password”也不好用了

现在,开发者们建议使用自适应的单射函数(adaptive one-way function)进行哈希映射

这种哈希映射,可以给存储的密码提供一个工作因子(work factor)

工作因子可以根据客户端的硬件水平,让用户在客户端花一秒左右的时间才能完成哈希映射

通过这种技术,可以防止黑客短时间内发动多次密码穷举,保证了用户密码的安全性。

而Spring Security框架可以直接使用 bcrypt, PBKDF2, scrypt和argon2等加密方式

这些加密方式就是上面的加密手段,可以大大提高用户密码的安全性。



小结:

可以说这篇文档上所写的密码的发展史,是一部开发者和黑客斗智斗勇的历史

当然数学家在其中也扮演了极其重要的角色

随着技术的发展,我们有理由相信,新的破解技术会不断地产生,新的加密手段也会应运而生

到时候,我们这些只会复制粘贴的小菜鸡应该能够看到更为精彩的现代密码学“神仙打架”啦!