1. Flutter Md5 加密
// 引入所需的库: utf8 用于编码, crypto 用于md5加密
import 'dart:convert';
import 'package:crypto/crypto.dart';
main() {
// 对"Hello"字符串进行md5加密并打印结果
print(md5.convert(utf8.encode("Hello")));
}
2. 为什么要签名验证
// 为保证http请求的安全性,需要进行签名验证,以下列出了进行签名验证的几个主要原因:
// 1. 验证请求来源是否合法
// 2. 检查请求参数是否被篡改
// 3. 确保请求的唯一性,防止请求被复制
// 对于需要用户登录后访问的信息,尤其需要进行签名验证来确保数据的安全性。
3. 签名验证实现原理
// 用户登录成功后,服务器会返回包含用户信息及salt的数据
// salt 是在用户注册时随机生成并经md5加密得到的,每个用户的salt都是独一无二的
// 当请求API时,需要在接口中加入sign签名以确保数据的安全性。
// 例如,传统的请求方式是这样的:
传统请求方式
// 而带有签名验证的请求方式则变为:
带签名验证的请求方式
// 签名的生成算法如下:
import 'dart:convert';
import 'package:crypto/crypto.dart';
getSign() {
Map json = {
"aid": 1,
"name": 'zhangsan',
"age": 20,
"sex": '男',
"salt": "xxxewrewqrqrwqrwqrwqr"
};
List jsonKeys = json.keys.toList();
// 对key进行排序
jsonKeys.sort();
var str = '';
// 将排序后的key-value对拼接成字符串
for (var i = 0; i < jsonKeys.length; i++) {
str += "${jsonKeys[i]}${json[jsonKeys[i]]}";
}
// 将拼接的字符串进行md5加密并打印
print(md5.convert(utf8.encode(str)));
}
4. 请求接口传入 sign
// 在实际请求接口时,我们需要将生成的sign参数添加到URL中,如:
请求接口带sign
5. 服务器端生成签名验证
// 服务器端需要进行以下步骤来验证客户端传来的sign:
// 1. 获取客户端传来的sign和其他参数
// 2. 使用uid查询数据库,获取当前用户的salt(32位)
// 3. 将URL中的数据和查询到的salt组合成json, 使用同样的算法生成签名
// 4. 比较服务器生成的签名和客户端传来的签名,如果相同则数据未被篡改
6. 请求的唯一性解决方案
// 为了防止请求参数被重复使用,我们需要确保每次的请求都是唯一的。
// 一种常见的做法是在请求参数中加入时间戳,并将其作为请求参数之一,加入到sign的生成算法中。
// 服务器会比较客户端的时间戳和服务器的当前时间,如果两者之间的时间差过大,则请求会被判定为无效。
// 如何解决时间差问题:
// 1. 启动应用时,获取本地时间,然后请求服务器获取其当前时间
// 2. 计算时间差并保存到本地存储
// 3. 每次请求接口时,将本地时间和时间差相加,得到一个更接近服务器时间的时间戳