我的NodeJS应用有三种变体。
第一个版本仅使用Node,并且 正常工作。
正在使用ExpressJS的应用程序的第二和第三版本是引起问题的版本。我不得不诉诸于ExpressJS,因为我会将应用程序部署到AWS Lambda,并且可能会为此目的使用ClaudiaJS。
此外,我正在使用Duo作为MFA,它将已通过身份验证的用户发送到Okta,以便可以解锁该用户的帐户。
HTML文件在所有3个实例中均不变。
在第一个简化实例中,应用程序按预期运行:
app.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}.`)
)
第三版(无法发布):
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);
我研究了各种资源,并尝试了许多不同的解决方案。请帮忙!
答案 0 :(得分:0)
好的,因此在同事的帮助下,我得以解决此问题。我正打算尝试以错误的方式访问请求中的数据。
这可行,并且更简单:
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()
}
})
希望这对其他人有帮助!