[英]How to post a subrequest with a json body to another server from NGINX http request object
Interface with Auth0 requiring a post request with a json body to retrieve the token and set it in the Header Authorization Bearer.与 Auth0 的接口需要带有 json 主体的发布请求以检索令牌并将其设置在 Header 授权承载中。 I have trouble to set the json body in the subrequest in the nginx js mdoule for the token.
我无法在令牌的 nginx js mdoule 的子请求中设置 json 主体。 Please advice
请指教
```
function introspectAccessToken(r) {
// Prepare Authorization header for the introspection request
var jsbody = {"grant_type" : "authorization_code",
"client_id" : r.variables.oauth_client_id,
"client_secret" : r.variables.oauth_client_secret,
"code" : r.args_code,
"redirect_uri":"http://office.etag-hk.com/login"};
var jsString = JSON.stringify(jsbody);
r.RequestBuffer = jsString;
// Make the OAuth 2.0 Token Introspection request
r.error("OAuth jsbody: " + jsString);
r.subrequest("/_oauth2_send_introspection_request",
function(reply) {
if (reply.status != 200) {
r.error("OAuth unexpected response from authorization server (HTTP " + reply.status +
"). " + reply.body);
r.return(401);
}
Thanks
I am doing something very similar and just got it 'mostly' working the way I would like just yesterday.我正在做一些非常相似的事情,只是让它“大部分”按照我昨天想要的方式工作。
Disclosure: I am a NUBE to NGINX.披露:我是 NGINX 的 NUBE。 I am posting what I did hopefully to help you, and to get any feedback on how I can make improvements.
我正在发布我所做的事情,希望能对您有所帮助,并获得有关如何改进的任何反馈。
My Use Case: I have many clients requesting data from a backend server.我的用例:我有许多客户端从后端服务器请求数据。 I need to cache the responses to reduce load on the backend, as well as authenticate to the backend server for the client.
我需要缓存响应以减少后端的负载,并为客户端对后端服务器进行身份验证。 The NGINX server will manage the ID/PWD and Token, the clients will just make requests.
NGINX 服务器将管理 ID/PWD 和 Token,客户端只会发出请求。 On the very first request, or when the token expires, NGINX needs to get a fresh token.
在第一个请求或令牌过期时,NGINX 需要获取新的令牌。 The authentication is completed with a POST request, passing the ID and Password in a JSON body.
身份验证通过 POST 请求完成,在 JSON 主体中传递 ID 和密码。
I would like the client never to see 401. I am using the NGINX JavaScript module as you are.我希望客户端永远不会看到 401。我正在使用 NGINX JavaScript 模块。
I turned off caching for now to make sure I have the authentication working.我现在关闭了缓存以确保身份验证正常工作。
Javascript: Javascript:
function introspectAccessToken(r)
{
r.log("introspectAccessToken - make a subrequest to _oauth2_send_request");
// Request Internal location "SEND REQUEST"
r.subrequest("/_oauth2_send_request",
{ method: 'POST',
body: JSON.stringify({ userName: "SERVICEID", password: "correcthorsebatterystaple" })
},
function(reply)
{
…
My body is static and for the moment, I have the ID and password in clear text in the code which is not ideal.我的身体是 static,目前,我的 ID 和密码在代码中以明文形式显示,这并不理想。 I like how you built your body up in a variable.
我喜欢你如何在一个变量中建立你的身体。 I think you need to put the jsString in your subrequest call rather than setting r.RequestBuffer.
我认为您需要将 jsString 放入您的子请求调用中,而不是设置 r.RequestBuffer。
In my.Conf file:在 my.Conf 文件中:
location /_oauth2_send_request {
internal;
proxy_method POST;
proxy_set_header accept "application/json";
proxy_set_header Content-Type "application/json";
proxy_pass https://backend.company.com/login;
}
The token is returned in the body.令牌在正文中返回。 I parse the body and get the token data.
我解析正文并获取令牌数据。 Initially I attempted to get the token with:
最初我试图通过以下方式获取令牌:
js_set $token myJavaScript.getToken;
in the config, but r.subrequest is an asynchronous call and that is not allowed in a variable handler.在配置中,但 r.subrequest 是异步调用,并且在变量处理程序中是不允许的。
So, I 'punted' and wrote the token data to a file.所以,我“踢”并将令牌数据写入文件。 This may be a BIG ERROR on my part, but it helped me to getting it to work.
这对我来说可能是一个大错误,但它帮助我让它发挥作用。
Here is more of my javascript:这是我的更多 javascript:
function(reply)
{
if (reply.status == 200)
{
r.log("introspectAccessToken: POST status:" + reply.status);
var response = JSON.parse(reply.responseBody);
var token = response["data"];
// Write the Token to a file -- to be read later.
writeToken(token);
return(200);
else
{
r.log("introspectAccessToken: failed POST status:" + reply.status);
r.return(401);
}
});
Now that the token is in a file, I can use the variable handler to read the file ( synchronously ) and return the token data.现在令牌在文件中,我可以使用变量处理程序来读取文件(同步)并返回令牌数据。 Conf file.
配置文件。
js_set $myToken myJavaScript.readToken;
Where I struggled for some time was getting the initial 401 authorized redirected back to NGINX and not to the client.我挣扎了一段时间的地方是将最初的 401 授权重定向回 NGINX 而不是客户端。 The directive error_page 401, in many different formats, simply did not seem to work and I even read in blogs and posts that it wouldn't work, but in others examples claiming it did work.
指令error_page 401,在许多不同的格式中,似乎根本不起作用,我什至在博客和帖子中读到它不起作用,但在其他示例中声称它确实起作用。 What I think was key was the line: proxy_intercept_errors on;
我认为关键是这一行:proxy_intercept_errors on;
After adding that, the initial 401 unauthorized error was redirected: error_page 401 = @Unauthorized;添加后,最初的401未授权错误被重定向:error_page 401 = @Unauthorized;
What I have now is as follows: 1: Client makes initial GET request to get some data.我现在拥有的如下: 1:客户端发出初始 GET 请求以获取一些数据。 The readToken function returns an empty string because token file does not exist.
readToken function 返回一个空字符串,因为令牌文件不存在。 The response from the backend is "401 Unauthorized".
来自后端的响应是“401 Unauthorized”。 2: The 401 is redirected, and the javascript makes a subrequest to the login with the ID/PWD.
2:401重定向,javascript对ID/PWD登录进行子请求。 3: The response is parsed and the token is written to the file.
3:解析响应并将令牌写入文件。 4: ???
4:??? The client gets a 404 Not Found code.
客户端收到 404 Not Found 代码。 This is what I want to improve.
这就是我想要改进的。 I would like another attempt made to the backend with the new token.
我想使用新令牌对后端进行另一次尝试。 5: Failing on the first attempt, the client performs a retry.
5:第一次尝试失败,客户端执行重试。 Now with a saved token on the NGINX server, the request is successful.
现在在 NGINX 服务器上使用保存的令牌,请求成功。
My full conf file:我的完整 conf 文件:
# Location of JavaScript code
js_import ./javascript/myJavaScript.js;
js_set $myToken myJavaScript.readToken;
server
{
listen 80;
access_log /var/log/nginx/access.log main1;
# This is run for every request.
location / {
# Make an Internal Redirect if Not Authorized.
proxy_intercept_errors on;
error_page 401 = @Unauthorized;
proxy_set_header accept "application/json";
proxy_set_header Content-Type "application/json";
proxy_set_header Authorization $myToken;
proxy_pass https://backend.company.com;
}
location @Unauthorized {
internal;
auth_request /_oauth2_token_introspection;
}
location = /_oauth2_token_introspection {
internal;
# Calls the javascript function
js_content myJavaScript.introspectAccessToken;
}
# Location in javascript subrequest.
location /_oauth2_send_request {
internal;
proxy_method POST;
proxy_set_header accept "application/json";
proxy_set_header Content-Type "application/json";
proxy_pass https://imos-plant-config-api-test.op-epg1mi.gm.com/tonic/login;
}
}
My full javascript:我的完整 javascript:
var fs = require('fs');
var MyTokeFile = "/etc/nginx/protectedFolder/mytoken.dat";
function writeToken(t)
{
var file = fs.writeFileSync(MyTokeFile, t)
}
function readToken(r)
{
try {
fs.accessSync(MyTokeFile, fs.constants.R_OK);
r.log('readToken: Has READ access : ' + MyTokeFile);
} catch (e) {
r.log('readToken: No READ access : ' + MyTokeFile);
return (""); // Return empty string if file cannot be read.
}
r.log("readToken:" + MyTokeFile )
var file = fs.readFileSync(MyTokeFile);
var token = file.toString();
return (token);
}
function introspectAccessToken(r)
{
r.log("introspectAccessToken - make a subrequest to _oauth2_send_request");
// Request Internal location "SEND REQUEST"
r.subrequest("/_oauth2_send_request",
{ method: 'POST',
body: JSON.stringify({ userName: "SERVICEID", password: "correcthorsebatterystaple" })
},
function(reply)
{
if (reply.status == 200)
{
r.log("introspectAccessToken: POST status:" + reply.status);
var response = JSON.parse(reply.responseBody);
var token = response["data"];
// Write the Token to a file -- to be read later.
writeToken(token);
r.return(200);
}
else
{
r.log("introspectAccessToken: failed POST status:" + reply.status);
r.return(401); // Unexpected response, return 'auth required'
}
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.