最近在使用minio文件服务器,来实现图片上传与展示功能,在展示的时候出现一个问题,就是图片在做鉴权时,minio提供的有效地址是真的拉跨,没法实现图片链接的有效鉴权功能,而且链接直接给出来的话也有风险。
后面想着加一个反向代理的方式,也就是Nginx做代理,这样就不会暴露图片的ip地址。但是,在做鉴权时遇到了麻烦,网络上大部分推荐lua脚本来实现鉴权的方式,在经过几天的不断试错,才最终将他实现,现在在此记录下。
工具:openresty(nginx集成lua模块,比较简单)
lua包需要下载lua-resty-http工具包,地址lua-resty-http,解压后将.lua文件放到 lualib\resty目录下就行。
实现思路:用户发送请求---> nginx ----->根据图片路径策略-----> 执行lua代码(发送http到后端token鉴权)----->通过就代理到具体图片服务器----->否则提示无权限
nginx关键代码
http {
# 定义全局变量
init_by_lua_block {
cjson = require "cjson";
http = require "resty.http";
}
server {
location ~^/(api)/image/(.*)$ {
rewrite_by_lua_block {
-- local cjson = require "cjson"
-- local http = require "resty.http"
local httpc = http.new()
local ngx = ngx
local headers = ngx.req.get_headers()
-- get请求参数中T就是token
local token = headers["token"]
local request_method = ngx.var.request_method
local args = nil
if "GET" == request_method then
args = ngx.req.get_uri_args()
elseif "POST" == request_method then
ngx.req.read_body()
args = ngx.req.get_post_args()
end
token = args["token"];
if not token then
ngx.header['Content-Type'] = 'text/plain; charset=utf-8';
ngx.status = ngx.HTTP_FORBIDDEN
ngx.say("您无权限浏览该图片。")
ngx.exit(200)
end
-- 字符串拼接
-- 你要实现token鉴权的服务,header和参数都给你实现了,根据实际需要选择
local url = "http://127.0.0.1:8080/image/checkToken?token="..token;
local res, err = httpc:request_uri(url, {method="GET", headers={["token"]=token}})
if not res then
ngx.header['Content-Type'] = 'text/plain; charset=utf-8';
ngx.say(cjson.encode({message = "Error getting response",status = ngx.HTTP_INTERNAL_SERVER_ERROR }));
ngx.exit(200)
end
if res.body == '0' then
ngx.header['Content-Type'] = 'text/plain; charset=utf-8';
ngx.say("您无权限浏览该图片。");
ngx.exit(200)
end
}
proxy_pass http://yourip:9000/$2;
}
}
}
Java后端代码
@RestController
@RequestMapping("/image")
public class TokenResource {
@RequestMapping("/checkToken")
public String checkToken(HttpServletRequest request, String token) {
System.out.println("程序进来了");
String header = request.getHeader("token");
System.out.println("头部token:" + header);
if (StringUtils.isEmpty(token)) {
System.out.println(token + ":0");
return "0";
}
if ("1".equals(token)) {
System.out.println(token + ":1");
return "1";
}
return "0";
}
}
当token校验通过,就不做拦截,lua代码执行完会走到nginx的转发路径上来
proxy_pass http://your_ip:9000/$2
~^/(api)/image/(.*)$ 写成 ~^/api/image/(.*)$ 时 proxy_pass 改为 http://your_ip:9000/$1