node.js - 无法在 NodeJS + ExpressJS 应用程序中发布
问题描述
我的 NodeJS 应用程序有三种变体。
第一个版本仅使用 Node,并且工作正常。
使用 ExpressJS 的应用程序的第二和第三版本是导致问题的版本。我不得不求助于使用 ExpressJS,因为我将把应用程序部署到 AWS Lambda,并且可能会为此目的使用 ClaudiaJS。
另外,我正在使用 Duo 进行 MFA,它将经过身份验证的用户发送到 Okta,以便可以解锁用户的帐户。
HTML 文件在所有 3 个实例中均未更改。
在第一个简化实例中,应用程序按预期工作:
应用程序.js
let http = require('http')
let url = require('url')
let qs = require('querystring')
let duo_web = require('./duo.js')
const ikey = 'LOREM'
const skey = 'LOREM'
const akey = 'LOREM'
const api_hostname = 'LOREM'
const post_action = ''
const okta = require('@okta/okta-sdk-nodejs');
const client = new okta.Client({
orgUrl: 'LOREM/',
token: 'LOREM' // Obtained from Developer Dashboard
});
/**
* Returns templated string with api_hostname and sig_request.
*
* @param {string} api_hostname - name of users API Hostname
* @param {string} sig_request - Signed request returned from Duo's sign_request
* @param {string} post_action - Name of the post_action url that will be posted
* to by the IFrame
*/
let IFrame = (api_hostname, sig_request, post_action) => {
return `<!DOCTYPE html>
<html>
<head>
<title>Duo Authentication Prompt</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<style>
body {
text-align: center;
}
iframe {
width: 100%;
min-width: 304px;
max-width: 620px;
height: 330px;
border: none;
}
</style>
</head>
<body>
<h1>Duo Authentication Prompt</h1>
<iframe id="duo_iframe"
title="Two-Factor Authentication"
data-host= ${api_hostname}
data-sig-request= ${sig_request}
data-post-action=${post_action}
>
</iframe>
<script src='https://api.duosecurity.com/frame/hosted/Duo-Web-v2.min.js'></script>
</body>
</html>`
}
/**
* Creates the server and listens for any POST/GET requests.
*/
const app = http.createServer((req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
if (method === 'GET') {
if (base_url === '/') {
let query = url.parse(req.url, true).query
let {username} = query
if (username) {
// initializes secondary authentication process
let sig_request = duo_web.sign_request(ikey, skey, akey, username)
let duo_frame = IFrame(api_hostname, sig_request, post_action)
// shows the IFrame
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(duo_frame)
} else {
res.writeHead(404, {'Content-Type': 'text/html'})
res.end(`Make sure you add a username: http://localhost:8080/?username=xxx,\
and appropriate configuration variables (ikey, skey, etc.). `)
}
}
} else if (method === 'POST') {
if (base_url) {
let request_body = ''
req.on('data', data => {
request_body += data.toString() // convert Buffer to string
});
req.on('end', () => {
let form_data = qs.parse(request_body)
let sig_response = form_data.sig_response
// verifies that the signed response is legitimate
let authenticated_username = duo_web.verify_response(ikey, skey, akey, sig_response)
if (authenticated_username) {
client.unlockUser(`${authenticated_username}`)
.then(user => {
console.log(user);
})
res.end(`${authenticated_username}, You've Been Dual Authenticated !`)
} else {
res.status(401).end()
}
})
}
}
})
module.exports = app
app.local.js
const app = require('./app')
const port = process.env.PORT || 8080
app.listen(port, () =>
console.log(`Server is listening on port ${port}.`)
)
现在,当我开始使用 ExpressJS 时,我遇到了一些问题,我的代码要么卡在 POST 请求中,我可以在控制台中看到“待定”状态,或者在下面的第三个版本中,我得到了浏览器中的“无法发布”和控制台中的 404。
第二个版本(请求永久挂起):
app2.js
'use strict'
const express = require('express')
var bodyParser = require("body-parser");
const app = express()
let url = require('url')
let qs = require('querystring')
let duo_web = require('./duo.js')
const ikey = 'LOREM'
const skey = 'LOREM'
const akey = 'LOREM'
const api_hostname = 'LOREM'
const post_action = ''
const okta = require('@okta/okta-sdk-nodejs');
const client = new okta.Client({
orgUrl: 'LOREM',
token: 'LOREM' // Obtained from Developer Dashboard
});
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/public'));
/**
* Returns templated string with api_hostname and sig_request.
*
* @param {string} api_hostname - name of users API Hostname
* @param {string} sig_request - Signed request returned from Duo's sign_request
* @param {string} post_action - Name of the post_action url that will be posted
* to by the IFrame
*/
let IFrame = (api_hostname, sig_request, post_action) => {
return `<!DOCTYPE html>
<html>
<head>
<title>Duo Authentication Prompt</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<style>
body {
text-align: center;
}
iframe {
width: 100%;
min-width: 304px;
max-width: 620px;
height: 330px;
border: none;
}
</style>
</head>
<body>
<h1>Duo Authentication Prompt</h1>
<iframe id="duo_iframe"
title="Two-Factor Authentication"
data-host= ${api_hostname}
data-sig-request= ${sig_request}
data-post-action=${post_action}
>
</iframe>
<script src='https://api.duosecurity.com/frame/hosted/Duo-Web-v2.min.js'></script>
</body>
</html>`
}
/**
* Creates the server and listens for any POST/GET requests.
*/
app.get('/', (req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
if (method === 'GET') {
if (base_url === '/') {
let query = url.parse(req.url, true).query
let {username} = query
if (username) {
// initializes secondary authentication process
let sig_request = duo_web.sign_request(ikey, skey, akey, username)
let duo_frame = IFrame(api_hostname, sig_request, post_action)
// shows the IFrame
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(duo_frame)
} else {
res.writeHead(404, {'Content-Type': 'text/html'})
res.end(`Make sure you add a username: http://localhost:8080/?username=xxx,\
and appropriate configuration variables (ikey, skey, etc.). `)
}
}
next();
}
})
app.post('/', (req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
if (method === 'POST') {
if (base_url) {
let request_body = ''
req.on('data', data => {
request_body += data.body.toString() // convert Buffer to string
})
req.on('end', () => {
let form_data = qs.parse(request_body)
let sig_response = form_data.sig_response
// verifies that the signed response is legitimate
let authenticated_username = duo_web.verify_response(ikey, skey, akey, sig_response)
if (authenticated_username) {
client.unlockUser(`${authenticated_username}`)
.then(user => {
console.log(user);
});
res.end(`${authenticated_username}, You've Been Dual Authenticated !`)
} else {
res.status(401).end()
}
})
}
}
})
module.exports = app
app2.local.js
const app = require('./app2')
const port = process.env.PORT || 8080
app.listen(port, () =>
console.log(`Server is listening on port ${port}.`)
)
第三个版本(得到一个不能 POST):
app3.js
'use strict'
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var app = express();
let url = require('url');
let qs = require('querystring');
let duo_web = require('./duo.js');
const ikey = 'LOREM'
const skey = 'LOREM'
const akey = 'LOREM'
const api_hostname = 'LOREM'
const post_action = ''
const okta = require('@okta/okta-sdk-nodejs');
const client = new okta.Client({
orgUrl: 'LOREM',
token: 'LOREM' // Obtained from Developer Dashboard
});
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));
/**
* Returns templated string with api_hostname and sig_request.
*
* @param {string} api_hostname - name of users API Hostname
* @param {string} sig_request - Signed request returned from Duo's sign_request
* @param {string} post_action - Name of the post_action url that will be posted
* to by the IFrame
*/
let IFrame = (api_hostname, sig_request, post_action) => {
return `<!DOCTYPE html>
<html>
<head>
<title>Duo Authentication Prompt</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<style>
body {
text-align: center;
}
iframe {
width: 100%;
min-width: 304px;
max-width: 620px;
height: 330px;
border: none;
}
</style>
</head>
<body>
<h1>Duo Authentication Prompt</h1>
<iframe id="duo_iframe"
title="Two-Factor Authentication"
data-host= ${api_hostname}
data-sig-request= ${sig_request}
data-post-action=${post_action}
>
</iframe>
<script src='https://api.duosecurity.com/frame/hosted/Duo-Web-v2.min.js'></script>
</body>
</html>`
}
/**
* Creates the server and listens for any POST/GET requests.
*/
app.get('/', (req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
if (method === 'GET') {
if (base_url === '/') {
let query = url.parse(req.url, true).query
let {username} = query
if (username) {
// initializes secondary authentication process
let sig_request = duo_web.sign_request(ikey, skey, akey, username)
let duo_frame = IFrame(api_hostname, sig_request, post_action)
// shows the IFrame
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(duo_frame)
next();
} else {
res.writeHead(404, {'Content-Type': 'text/html'})
res.end(`Make sure you add a username: http://localhost:8080/?username=xxx,\
and appropriate configuration variables (ikey, skey, etc.). `)
}
}
next();
}
})
app.post('/', urlencodedParser, (req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
if (method === 'POST') {
if (base_url === '/') {
let request_body = '';
req.on('data', (chunk) => {
request_body.push(chunk);
}).on('end', () => {
request_body = Buffer.concat(request_body).toString();
let form_data = qs.parse(request_body)
let sig_response = form_data.sig_response
// verifies that the signed response is legitimate
let authenticated_username = duo_web.verify_response(ikey, skey, akey, sig_response)
if (authenticated_username) {
client.unlockUser(`${authenticated_username}`)
.then(user => {
console.log(user);
});
res.end(`${authenticated_username}, You've Been Dual Authenticated !`)
} else {
res.status(401).end()
}
})
}
}
next();
})
module.exports = app
app3.local.js
const app = require('./app3')
const port = process.env.PORT || 8080
app.listen(port, () =>
console.log(`Server is listening on port ${port}.`)
)
在第二个和第三个实例中,应用程序永远不会在 POST 请求中到达此代码块:
req.on('data', (chunk) => {
request_body.push(chunk);
我查看了各种资源,并尝试了许多不同的解决方案。请帮忙!
解决方案
Ok so with the help of a colleague I was able to resolve this. I was going about trying to access the data in the request in the wrong way.
This works, and is much simpler:
app.post('/', urlencodedParser, (req, res, next) => {
let base_url = url.parse(req.url).pathname
let method = req.method
let sig_response = req.body.sig_response
console.log(req.body.sig_response)
// verifies that the signed response is legitimate
let authenticated_username = duo_web.verify_response(ikey, skey, akey, sig_response)
if (authenticated_username) {
client.unlockUser(`${authenticated_username}`)
.then(user => {
console.log(user);
});
res.end(`${authenticated_username}, You've Been Dual Authenticated !`)
} else {
res.status(401).end()
}
})
Hope this helps others!
推荐阅读
- excel - 在第一行中查找第一个空白列
- css - 为什么高度:100% 和宽度 100% 不起作用
- javascript - 用 mongoDB 创建的时刻
- css - CSS 范围为 1 个 div 及其所有子元素
- javascript - 如何使用猫鼬存储日期时间?
- machine-learning - Transformer 模型如何计算自注意力?
- sql - 无法将 Void 分配给隐式类型变量 MVC 5
- python - 我想用下一行字更改“未命名”列的列名。我对python有点陌生
- ios - 启动本地服务器 iOS 并将其加载到 WKWebView
- android - .findViewById() 返回 null