Мои внешние маршруты настроены так, что форма POST отправляет данные на мой сервер, а мой файл сервера проверяет ввод.Затем он принимает эти данные и передает их в другой файл, который затем выполняет аутентификацию.У меня есть несколько вопросов по этому поводу:
1) Нужно ли передавать данные асинхронно?2) Способ, которым я в настоящее время передаю синхронный?Если это нужно изменить 3) Если я хочу передать свои переменные в этот файл, и он использует асинхронный водопад (я считаю, что я не могу передать переменные в первую функцию), я должен создать основную функцию, которая имеет две подфункции (однудля хранения переменных и одной для выполнения асинхронного водопада)?
Я новичок в Node.js, поэтому только начал изучать концепцию асинхронной функциональности.Любые советы, помощь или вопросы, пожалуйста, дайте мне знать.Если я что-то пропустил, пожалуйста, спросите
Функция моего сервера такова:
//Route for POST requests to Login
//First Sanitise input!
app.route('/login').post([
//ACCOUNTTYPE CHECKS -------------------------------------------------------------------------------
check('accountType').exists()
.trim()
.isAlpha()
.isLength({
min: 8,
max: 10
})
.matches(/(Production|Internal)/).withMessage('Must be either \'Production\' or \'Internal\'\!')
.escape(),
//CUSTOMERID CHECKS --------------------------------------------------------------------------------
check('customerID').exists()
.trim()
.isNumeric()
.isInt()
.isLength({
max: 40
})
.escape(),
//CLIENTID CHECKS ---------------------
check('clientID').exists()
.trim()
.isAlphanumeric()
.isLength({
max: 40
})
.escape(),
//CLIENTSECRET CHECKS ---------------------
check('clientSecret').exists()
.trim()
.isAlphanumeric()
.isLength({
min: 0,
max: 45
})
.escape(),
//USERNAME CHECKS ---------------------
check('username').exists()
.trim()
.isEmail()
.isLength({
min: 0,
max: 100
})
.escape(),
//PASSWORD CHECKS ---------------------
check('password').exists()
.trim()
.isLength({
min: 0,
max: 100
})
.escape()
], urlencodedParser, (req, res) => {
let now = new Date().toString(),
log = `${now}: ${req.method} ${req.url}`,
sess = req.session;
console.log(req.body);
fs.appendFile('server-requests.log', log + '\n', (err) => {
if (err) {
console.log('Unable to append to server-requests.log!');
}
});
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
//return a bad status and array of errors
//if the validation fails
// return res.status(422).json({
// errors: errors.array()
// });
//OR:
return res.render('login.hbs', {
currentYear: new Date().getFullYear(),
//This does not work realtime - FIX TODO
currentTime: moment().format('MMMM Do YYYY - h:mm:ss a'),
data: {},
errors: errors.mapped()
});
// If there aren't any errors, proceed to save variable data and use 2.0
} else {
//Handle with event emiitters and make asynchronous - TODO
const data = matchedData(req);
console.log('Data stored in session:')
console.log('Sanitised:', data);
//Store Form Data in session variables
sess.accountType = data.accountType,
sess.customerID = data.customerID,
sess.clientID = data.clientID,
sess.clientSecret = data.clientSecret,
sess.username = data.username,
sess.password = data.password;
console.log('Sanitised POST Form! Now initialising request.');
req.flash('success', 'Successful POST request, proceeding to authorisation...)');
//Make asynchronous?
//use each function and get variables
auth.saveVariables(sess.accountType, sess.customerID, sess.clientID, sess.clientSecret, sess.username, sess.password);
auth.asyncWaterfall(callback)
res.redirect('/index');
//Or alternatively should it redirect with a query string?
// const url = require('url');
// app.get('/index', function (req, res) {
// res.redirect(url.format({
// pathname: "/",
// query: {
// "acccountType": 1,
// "customerID": 2,
// "clientID": 3,
// "clientSecret": 4,
// "username": 5,
// "password": 6
// }
// }));
// });
}
})
Вот начало кода моего контроллера аутентификации:
const saveVariables = (accountType, customerID, clientID, clientSecret, username, password, callback) => {
//Test parameters
if (accountType.type() !== String || customerID.type() !== String || clientID.type() !== String || clientSecret.type() !== String || username.type() !== String || password.type() !== String) {
let fields = [accountType, customerID, clientID, clientSecret, username, password];
test(fields);
}
accountType,
customerID,
clientID,
clientSecret,
username,
password;
}
const test = (array) => {
array.forEach((field) => {
let errorString;
if (field.type() !== String) {
errorString += `The field ${field} is not a String. Type: ${field}.`
}
return errorString;
})
}
//This const creates the auth URL and auth code grant URL. It also assigns the host URL.
const createAuthURL = (callback) => {
//If the paramter test passes then proceed
if (accountType === "Production") {
try {
let authURL = `https://${prodURL}${url1}`,
authCodeURL = `https://${prodURL}${url2}`,
host = prodURL;
} catch (e) {
console.log(`Error occurred when assigning url variables (Production). Error: ${e}`);
console.error('Error occurred when assigning url variables (Production). Error:', e);
}
} else if (accountType === "Internal") {
try {
let authURL = `https://${internURL}${url1}`,
authCodeURL = `https://${internURL}${url2}`,
host = internURL;
} catch (e) {
console.log(`Error occurred when assigning url variables (Internal). Error: ${e}`);
console.error('Error occurred when assigning url variables (Internal). Error:', e);
}
} else {
console.log(`Bad String Input into auth URL! Entry: ${accountType}`);
console.error('Bad String Input into auth URL: ', accountType);
}
}
const asyncWaterfall = (req, res) => {
//Asynchronous Waterfall Call of 'Getting Access Tokens' (Stages 1-3)
async.waterfall([
getCookieData,
getAuthCode,
getAccessToken
], (err, result) => {
if (err) {
alert('Something is wrong!');
}
return alert('Done!');
});
//STAGE 1 - USE CUSTOMER DETAILS TO RETRIEVE COOKIE AND CSRF SESSION DATA
getCookieData = async (callback) => {
//For testing purposes - Remove after development
console.log(`The type of account used is: ${accountType}`);
console.log(`The customerID used is: ${customerID}`);
console.log(`The clientID used is: ${clientID}`);
console.log(`The client secret used is: ${clientSecret}`);
console.log(`The username used is: ${username}`);
console.log(`The password used is: ${password}`);
console.log(`Making a URL request to: ${authURL}`);
//If the paramter test passes then proceed
var options = {
//Type of HTTP request
method: 'POST',
//URI String
uri: authURL,
//HTTP Query Strings
qs: {
'client_id': clientID
},
//HTTP Headers
headers: {
'cache-control': 'no-cache',
'Accept': 'application/json',
'Host': host,
'Content-Type': 'application/json'
},
//HTTP Body
body: {
'username': username,
'password': password
},
json: true // Automatically stringifies the body to JSON
//resolveWithFullResponse: true // Get the full response instead of just the body
//simple: false // Get a rejection only if the request failed for technical reasons
};
console.log(`Beginning HTTP POST Request to ${authURL}...`);
//await literally makes JavaScript wait until the promise settles, and then go on with the result.
await rp(options)
.then((parsedBody) => {
//POST Succeeded...
Console.log('Successful HTTP POST!');
try {
let csrf = response.body('csrftoken'),
ses = response.body('session'),
sesk = `session=${ses}`;
} catch (e) {
console.log(`STAGE 1 - Error occurred when assigning url variables. Error: ${e}`);
console.error('STAGE 1 - Error occurred when assigning url variables. Error:', e);
}
console.log(`Successful grab of the cookie: ${ses} and csrf token: ${csrf}. Getting authorisation code now!`);
//Asynchronous callback for the next function - return = defensive architecture
return callback(null, authCodeURL, customerID, clientID, csrf, sesk);
})
.catch((err) => {
if (res.statusCode == 400) {
console.log(`Error Message: ${res.body.message}. Status: ${res.body.status}`);
console.error('Error Message:', res.body.message, 'Status:', res.body.status);
} else if (res.statusCode == 401) {
console.log(`Error Message: ${res.body.message}. Status: ${res.body.status}`);
console.error('Error Message:', res.body.message, 'Status:', res.body.status);
} else {
console.log(`Failed to retrieve the cookie data! Error: ${error}`);
console.error('Failed to retrieve the cookie data! Error:', error);
}
});
},
//STAGE 2 - USE COOKIES AND CSRF TOKEN TO GET AUTH CODE
//Is the word async needed? it is not asyncchronous but sequential
getAuthCode = async (authCodeURL, customerID, clientID, csrf, sesk, callback) => {
//Make sure all the data is in string format - Run Time Tests
if (authCodeURL !== String || cutomerID !== String || clientID !== String || csrf !== String || sesk !== String) {
let fields = [authCodeURL, cutomerID, clientID, csrf, sesk];
test(fields);
}
//If successful, proceed:
var options = {
method: 'POST',
uri: authCodeURL,
qs: {
'client_id': clientID,
'response_type': 'code',
'scope': 'all'
},
headers: {
'X-CSRF-TOKEN': csrf,
'Accept': 'application/json',
'Cookie': sesk,
'Content-Type': 'application/json'
},
body: {
'customer_id': customerID
},
json: true // Automatically stringifies the body to JSON
};
console.log(`Beginning HTTP POST Request to ${authCodeURL}...`);
//await literally makes JavaScript wait until the promise settles, and then go on with the result.
await rp(options)
.then((parsedBody) => {
//POST Succeeded...
Console.log('Successful HTTP POST!');
try {
let authCode = response.body.JSON('auth_code'),
swapurl = `https://${host}${url3}`;
} catch (e) {
console.log(`STAGE 2 - Error occurred when assigning url variables. Error: ${e}`);
console.error('STAGE 2 - Error occurred when assigning url variables. Error:', e);
}
console.log(`The authorisation Code is ${authcode}. Getting Access Token now!`);
//Asynchronous callback for the next function - return = defensive architecture
return callback(null, swapURL, clientID, clientSecret, authCode);
})
.catch((err) => {
if (res.statusCode == 400) {
console.log(`Error Message: ${res.body.message}. Extra: ${res.body.extra}`);
console.error('Error Message:', res.body.message, 'Extra:', res.body.extra);
} else {
console.log(`Failed to retrieve the authorisation code! Error: ${error}`);
console.error('Failed to retrieve the authorisation code! Error: ', error);
}
});
},
//STAGE 3 - USE AUTH CODE TO GET ACCESS TOKEN
//ASYNC NEEDED?
getAccessToken = async (swapURL, clientID, clientSecret, authCode, callback) => {
//Make sure all the data is in string format - Run Time Tests
if (swapURL !== String || clientSecret !== String || clientID !== String || authCode !== String) {
let fields = [swapURL, clientSecret, clientID, authCode];
test(fields);
}
//If successful, proceed:
var options = {
method: 'POST',
uri: swapURL,
qs: {
'client_id': clientID,
'grant_type': 'authorization_code',
'client_secret': clientSecret,
'code': authCode
},
json: true // Automatically stringifies the body to JSON
};
console.log(`Beginning HTTP POST Request to ${swapURL}...`);
//await literally makes JavaScript wait until the promise settles, and then go on with the result.
await rp(options)
.then((parsedBody) => {
//POST Succeeded...
Console.log('Successful HTTP POST!');
try {
let accessToken = response.body('access_token'),
refreshToken = response.body('refresh_token');
} catch (e) {
console.log(`STAGE 3 - Error occurred when assigning url variables. Error: ${e}`);
console.error('STAGE 3 - Error occurred when assigning url variables. Error:', e);
}
console.log(`The access Token is ${accessToken} and the refreshToken which is ${refreshToken}! These are only valid for 2 hours!`);
//Asynchronous callback for the waterfall - return = defensive architecture
return callback(null, 'done');
})
.catch((err) => {
console.log(`Failed to retrieve the access/refresh Token! Error: ${error}`);
console.error('Failed to retrieve the access/refresh Token! Error:', error);
});
}
}