nginx基于Post请求参数值做代理

840 阅读2分钟

背景

公司内部重构了一套统一身份认证系统。为了兼容老的基于OAuth2.0协议的身份认证系统,经过分析决定在老系统的F5和认证服务之间搭配两台nginx服务器。通过F5负载均衡到两台nginx服务器,nginx服务器根据请求的client_id代理到新的认证服务,逐步实现新旧系统迁移。

调研

老系统采用的是OAuth2.0协议,认证服务一系列接口由Post和Get请求组成。nginx可通过nginx内置变量$query_string或$args获取到请求中的参数值,可通过$request_body获取到客户端请求的报文体。问题就出现在获取$request_body这里,使用过程中发现获取Post请求中某一个参数的值并没有实现(Content-Type为application/x-www-form-urlencoded)。

针对该问题有三种实现方式:

  1. 修改nginx源码实现。
  2. nginx添加Lua模块,编写Lua脚本实现。
  3. nginx升级为OpenResty,同样编写Lua脚本实现。

经商议决定采用第二种方式实现。

知识补充

OAuth2.0:OAuth 2.0 是用于授权的行业标准协议。OAuth 2.0 侧重于客户端开发人员的简单性,同时为 Web 应用程序、桌面应用程序、移动电话和客厅设备提供特定的授权流程。OAuth2.0在认证和授权过程中涉及的三方包括:服务提供方(用户使用服务提供方来存储受保护的资源)、用户(存放在服务提供方的受保护的资源的拥有者)、客户端(要访问服务提供方资源的第三方应用,通常是网站,。在认证过程之前,客户端要向服务提供方申请客户端标识,上面提到的client_id就是这里的客户端标识)。

OpenResty:OpenResty 是一个成熟的网络平台,它集成了我们的nginx核心的增强版,我们的LuaJIT增强版,许多精心编写的Lua库,许多高质量的第三方Nginx模块,以及他们的大多数外部依赖关系。它旨在帮助开发人员轻松 构建可扩展的 Web 应用程序、Web 服务和动态 Web 网关。

实施

nginx的location配置

location  / {
	# get和post请求都代理
	set $client_id  $arg_client_id;
	# proxy_pass地址 
	set $target_url  "";
	rewrite_by_lua_block {
		-- 如果是Post请求,获取到client_id的值
		if ngx.var.request_method == "POST" then
				ngx.req.read_body()
				if ngx.var.client_id == "" 
					then ngx.var.client_id = ngx.req.get_post_args()["client_id"] 
				end
		end
		-- 如果client_id是要迁移的client_id,则代理到新的地址,否则还是访问老的
		local  migration_client_id = ( ngx.var.client_id == "firstclientid" or ngx.var.client_id == "secondclientid")
		if migration_client_id then
			ngx.var.target_url = "http://auth";
		else
			ngx.var.target_url = "http://old_auth";
		end 
	}
	access_log logs/log-access.log logFormat;
	proxy_pass $target_url;
}

注意这里的Content-Type为application/x-www-form-urlencoded,multipart/form-data、application/json等其他方式需要不同的配置方式。

总结

  • nginx提供多种模块可安装使用。
  • nginx的指令执行不是按照配置的先后顺序执行,是按阶段执行的。

欢迎留言交流讨论。