背景
公司内部重构了一套统一身份认证系统。为了兼容老的基于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)。
针对该问题有三种实现方式:
- 修改nginx源码实现。
- nginx添加Lua模块,编写Lua脚本实现。
- 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的指令执行不是按照配置的先后顺序执行,是按阶段执行的。
欢迎留言交流讨论。