前言

使用nginx http_auth_request_module和PHP(也可以使用其他的编程语言,这里以PHP为例)实现临时文件链接示例。原理是使用签名和时间戳。

  1. 文件服务器与API服务器不需要联网
  2. 可以自定义文件到期时间
  3. 算法对服务器CPU占用很低
  4. 非常简单
  5. 安全性取决于你的签名密钥复杂性

注意:签名密钥泄露将意味着别人可以利用该密钥生成有效的签名从而进行文件访问。如果密钥泄露请及时更换密钥。

生成临时文件链接

示例PHP代码

1
2
3
4
$path=$_GET["path"]; //路径
$t=strtotime('+24 hours'); //链接过期时间
$sign_key='$2y$10$OG2rNxa/1Hs/a61adREv0.QwcjuPZLr3VoG5o5LxSFAXxmzC5VJ1K'; //签名密钥
echo "http://example.com/".$path."?et=$t&sign=".hash("sha256","/$path$t$sign_key");

配置文件服务器

配置nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
location / { #需要鉴权的路径
auth_request /auth;
location ~ /* {}
}

location = /auth {
internal;
proxy_pass http://localhost/check_token.php; #鉴权服务器地址
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}

说明:通过获取请求头X-Original-URI来获取用户访问的链接并根据情况进行允许或拒绝,状态码200为允许,403为拒绝。

示例 check_token.php 代码

1
2
3
4
5
6
$sign_key='$2y$10$OG2rNxa/1Hs/a61adREv0.QwcjuPZLr3VoG5o5LxSFAXxmzC5VJ1K'; //签名密钥
$parsed_url = parse_url($_SERVER['HTTP_X_ORIGINAL_URI']);
parse_str($parsed_url["query"], $params);
if(!(isset($params["et"],$params["sign"]) && $params["et"] && $params["sign"] && $params["et"] >= time() && hash("sha256",$parsed_url["path"].$params["et"].$sign_key) == $params["sign"])){
http_response_code(403);
}

因为PHP运行时如果出现错误可能响应200状态码,将会导致http_auth_request_module误认为允许访问。建议在php配置文件中将 display_errors 设置为 Off (推荐)或者在 check_token.php 文件代码前面添加以下代码防止报错响应200状态码。

1
2
3
4
5
6
error_reporting(E_ALL);
ini_set('display_errors', 0);
function errorHandler($errno, $errstr, $errfile, $errline) {
http_response_code(500);
}
set_error_handler("errorHandler");