由于有需求要实现内外网双IP访问同一个应用,但是当前已部署的应用使用的cas+shiro的跳转url在spring的配置xml中写死的,所以需要实现判断来源HOST动态单点登录和跳转
部分响应体中写死了IP需要替换
使用Nginx+Lua脚本,body_filter_by_lua*替换响应体中的IP,也可以使用Nginx内置模块ngx_http_sub_filter_module ,或第三方模块replace-filter-nginx-module
因为替换内容后长度不一致了,需要在
header_filter_by_lua*
中加入ngx.header.content_length = nil
置空内容长度
-- body_filter_by_lua_file:
-- 获取当前响应数据
local chunk, eof = ngx.arg[1], ngx.arg[2]
local cjson = require("cjson");
local req_headers = ngx.req.get_headers() -- 请求头
local resp_headers = ngx.resp.get_headers() -- 响应头
-- 定义全局变量,收集全部响应
if ngx.ctx.buffered == nil then
ngx.ctx.buffered = {
}
end
-- 如果非最后一次响应,将当前响应赋值
if chunk ~= "" and not ngx.is_subrequest then
table.insert(ngx.ctx.buffered, chunk)
-- 将当前响应赋值为空,以修改后的内容作为最终响应
ngx.arg[1] = nil
end
-- 如果为最后一次响应,对所有响应数据进行处理
if eof then
-- 获取所有响应数据
local whole = table.concat(ngx.ctx.buffered)
ngx.ctx.buffered = nil
-- 内容有指定IP
if whole
-- 判断响应Host是否为客户端访问Host
and not string.match(whole, ngx.var.http_host)
then
-- ngx.log(ngx.ERR, "body_filter_by_lua::::响应内容:》》》\n", whole, "\n《《《")
-- 替换外网IP,需在server或location中设置以下两个变量
-- set $outerIP "100%.100%.100%.100"; # 外网IP
-- set $insideIP "172%.16%.0%.91"; # 内网IP
whole = string.gsub(whole, ngx.var.insideIP, ngx.var.outerIP)
-- 重新赋值响应数据,以修改后的内容作为最终响应
end
ngx.arg[1] = whole
end
方案一
- 使用Nginx反向代理
缺点很明显:登录CAS的URL中的
service
参数不能替换,而且无法做判断,可自定义程度不高
location /test {
proxy_headers_hash_max_size 51200;
proxy_headers_hash_bucket_size 6400;
proxy_connect_timeout 500s;
proxy_read_timeout 500s;
proxy_send_timeout 500s;
proxy_pass http://server/test;
proxy_set_header Host $host:$server_port;
#proxy_set_header Host $http_host;
#proxy_set_header Host $server_addr:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 修改响应头中的"Location"和"Refresh"字段,只能替换host部分,参数部分无法替换,非常重要
# https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
#proxy_redirect $scheme://$server_addr:$server_port/ /;
#proxy_redirect $scheme://$server_addr:$server_port/ $scheme://$http_host/;
#proxy_redirect ~^http://172.16.0.1:81(.*) http://100.100.100.100:81$1;
proxy_redirect ~^http://172.16.0.91:81(.*) $scheme://$http_host$1;
#proxy_set_header REMOTE-HOST $server_addr;
proxy_set_header X-FORWARDED-HOST $server_addr;
proxy_set_header X-FORWARDED-PORT $server_port;
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
# response中set-cookie的domain转换
#proxy_cookie_domain $server_addr $host;
}
方案二
使用纯Nginx+Lua实现
lua-nginx-module
时序图,点击链接后向上滑动
- access_by_lua* 替换请求头Host和
service
参数
local uri_args = ngx.req.get_uri_args()
local outerIP = "100%.100%.100%.100"
local insideIP = "172%.16%.0%.91"
if uri_args["service"] then
uri_args["service"] = string.gsub(uri_args["service"], outerIP, insideIP)
ngx.req.set_uri_args(uri_args)
end
此方式可以使用Nginx全局变量实现,但可自定义程度范围不大
if ($is_args = "?"){
}
if ($arg_service){
set $arg_service "http://172.16.0.91:81/test/login";
}
- header_filter_by_lua* 替换响应头Location和Refresh
local resp_headers = ngx.resp.get_headers() -- 响应头
local resp_location = resp_headers.location -- 响应地址
local outerIP = "100%.100%.100%.100"
local insideIP = "172%.16%.0%.91"
if resp_location ~= nil
-- 判断响应Host是否为客户端访问Host
and not string.match(ngx.header.location, ngx.var.http_host)
then
ngx.header['location'] = string.