现有情况是公司以Nginx做文件服务器,随着用户越来越多,项目越来越多,出现任意用户都可以访问所有文件的问题。想要对Nginx下的文件进行访问的控制,基于用户名和密码的访问控制太单一,无法满足需求。因此设计了每次都有后端动态生成url的方式,让用户访问,类似于阿里云OSS的访问方式。采集Nginx+Lua模块的办法。验证方法使用的md5和时间双重验证
准备
- Centos 7.5
- LuaJIT-2.0.5.tar.gz
- nginx-1.17.3.tar.gz
- lua-nginx-module-0.10.14.tar.gz(不能使用0.10.15版本,后期会出现缺少模块的bug)
安装
- 将上面三个文件上传到root目录下,然后解压
tar zxvf LuaJIT-2.0.5.tar.gz
tar zxvf lua-nginx-module-0.10.14.tar.gz
tar zxvf nginx-1.17.3.tar.gz
- 安装LuaJIT
cd /LuaJIT-2.0.5
make && make install
- 查看是否安装成功
# 查看 Nginx 是否安装成功
/usr/local/nginx/sbin/nginx -v
# nginx version: nginx/1.17.3 则表示安装成功
# 可能出现以下错误,则需要建立软链接:/usr/local/nginx/sbin/nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
- 配置Nginx环境变量,方便进行Nginx服务的启动与停止
vi /etc/profile
在文件结尾加入
PATH=$PATH:/usr/local/nginx/sbin
export PATH
- Nginx命令
#启动nginx
nginx
#停止nginx
nginx -s stop
#重启nginx
nginx -s reload
- 防火墙开发80端口
自己后面想配置的Nginx端口是多少,就设置成多少
# 永久开始80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
# 重启防火墙
firewall-cmd --reload
修改配置
vi /usr/local/nginx/conf/nginx.conf
在配置文件中server节点下加入location
#修改掉原来的过滤器
#location / {
# root html;
# index index.html index.htm;
#}
location / {
access_by_lua '
-- 获取请求路径,不包括参数。例如:/group1/M00/00/00/wKjlpltF-K-AZQQsAABhhboA1Kk469.png
local uri = ngx.var.uri;
-- 获取请求参数
local args = ngx.req.get_uri_args();
-- 获取请求参数中时间戳信息,传入的是毫秒
local ts = args["ts"];
-- 获取请求参数中 token 信息
local token1 = args["token"];
local errs = "没有访问权限" --定义错误提示消息
-- 更新系统缓存时间戳
ngx.update_time();
-- 获取当前服务器系统时间,ngx.time() 获取的是秒
local getTime = ngx.time() * 1000;
-- 计算时间差
local diffTime = tonumber(ts) - getTime;
-- md5 加盐加密
local token2 = ngx.md5(tostring(uri) .. "salt" .. tostring(ts));
--时间无效
if (tonumber(diffTime) <= 0) then
ngx.status = ngx.HTTP_FORBIDDEN;
ngx.say(errs);
ngx.exit(200) ;
end
if token1 ~= token2 then
-- 校验不通过
ngx.status = ngx.HTTP_FORBIDDEN;
ngx.say(errs);
ngx.exit(200);
end
';
#校验通过,允许访问资源
root html;
}
加入上面代码后,重启Nginx
生成url
下面是后端用Java代码生成所需的url的参数后缀
// 获取当前系统所在服务器的时间,毫秒单位
// 注意,当前系统不一定是 Nginx 所在服务器
long milliseconds = System.currentTimeMillis();
// 添加有效期时间,假设该链接有效期为 1 天,即 86400000
// 计算毫秒时,切记转换为 Long 类型进行运算,避免超出 int 类型的范围
// 自己测试时,为了方便,可以设置为 1 分钟之类的
System.out.println("当前系统时间:" + milliseconds);
milliseconds += 1L * 24 * 60 * 60 * 1000;
// milliseconds += 60L * 1000;
// 计算 token 信息
// 请求的资源路径
String requestResources = "/file/333.jpg";
// “关键字” 值,和 Nginx 服务器上的保持一致即可
String salt = "salt";
// 加密前的字符串:请求的资源路径 + “盐” 值 + 时间戳
String beforeEncryptionString = requestResources + salt + milliseconds;
// 这里使用 Spring 提供的 md5 加密工具进行 md5 加密
String token = DigestUtils.md5DigestAsHex(beforeEncryptionString.getBytes());
String url = requestResources + "?ts=" + milliseconds + "&token=" + token;
System.out.println("请求的 url 为:");
System.out.println(url);
运行代码输出url
测试访问
在浏览器输入Nginx所在服务器ip+端口号+上一步生成的url和参数,结果看到了Nginx下存储的文件
随便修改一下后面的token,测试不正确的网址
在实现这个功能时,参考了https://blog.csdn.net/hochenchong/article/details/81057603的博文