Node. js sets CORS cross-origin requests to share sample code with multiple domain name whitelists

Source: Internet
Author: User
This article mainly introduces Node. js sets the multi-domain name whitelist Method for CORS requests. The sample code in this article is very detailed. I believe it has some reference value for everyone. Let's take a look at it. This article mainly introduces Node. js sets the multi-domain name whitelist Method for CORS requests. The sample code in this article is very detailed. I believe it has some reference value for everyone. Let's take a look at it.

CORS

Speaking of CORS, I believe the front end is no stranger. I will not talk about it here. For details, please refer to this article.

CORS is mainly used to configure the Access-Control-Allow-Origin attribute in the Response Header for the domain name that you Allow this interface to Access. The most common settings are:

Res. header ('access-Control-Allow-origin', '*'); res. header ('access-Control-Allow-credentials', 'true'); // allows the server to send Cookie data

However, this setting is the simplest and most insecure. It indicates that this interface allows all domain names to send cross-origin requests to it. However, in actual business, it is expected that this interface only allows cross-origin request permissions for one or more websites, not all.

So, you must be smart. Isn't it easy to write a regular expression for multiple domain name whitelists? No, Just configure the Access-Control-Allow-Origin attribute to multiple domain names separated by commas?

As shown below:

Res. header ('access-Control-Allow-origin', '* .666.com'); // or the following res. header ('access-Control-Allow-origin', 'a .666.com, B .666.com, c.666.com ');

It is a pity that such a statement is invalid. In Node. js, the Access-Control-Allow-Origin attribute in the Response Header of res cannot match the regular expression except (*), and domain names cannot be separated by commas. That is to say, the attribute value of Access-Control-Allow-Origin can only be set to a single string or (*) of the identified domain name (*).

Since we want to allow multiple domain names and do not want to use insecure * wildcards, is it really impossible to configure CORS for the multi-domain white list?

CORS for multi-domain white lists can indeed be implemented. It's just a bit of a curve to save the country.

How CORS is implemented for multiple domain name whitelists

For details, refer to the core code of the cors Library:

(function () { 'use strict'; var assign = require('object-assign'); var vary = require('vary'); var defaults = { origin: '*', methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', preflightContinue: false, optionsSuccessStatus: 204 }; function isString(s) { return typeof s === 'string' || s instanceof String; } function isOriginAllowed(origin, allowedOrigin) { if (Array.isArray(allowedOrigin)) { for (var i = 0; i < allowedOrigin.length; ++i) { if (isOriginAllowed(origin, allowedOrigin[i])) {  return true; } } return false; } else if (isString(allowedOrigin)) { return origin === allowedOrigin; } else if (allowedOrigin instanceof RegExp) { return allowedOrigin.test(origin); } else { return !!allowedOrigin; } } function configureOrigin(options, req) { var requestOrigin = req.headers.origin, headers = [], isAllowed; if (!options.origin || options.origin === '*') { // allow any origin headers.push([{ key: 'Access-Control-Allow-Origin', value: '*' }]); } else if (isString(options.origin)) { // fixed origin headers.push([{ key: 'Access-Control-Allow-Origin', value: options.origin }]); headers.push([{ key: 'Vary', value: 'Origin' }]); } else { isAllowed = isOriginAllowed(requestOrigin, options.origin); // reflect origin headers.push([{ key: 'Access-Control-Allow-Origin', value: isAllowed ? requestOrigin : false }]); headers.push([{ key: 'Vary', value: 'Origin' }]); } return headers; } function configureMethods(options) { var methods = options.methods; if (methods.join) { methods = options.methods.join(','); // .methods is an array, so turn it into a string } return { key: 'Access-Control-Allow-Methods', value: methods }; } function configureCredentials(options) { if (options.credentials === true) { return { key: 'Access-Control-Allow-Credentials', value: 'true' }; } return null; } function configureAllowedHeaders(options, req) { var allowedHeaders = options.allowedHeaders || options.headers; var headers = []; if (!allowedHeaders) { allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers headers.push([{ key: 'Vary', value: 'Access-Control-Request-Headers' }]); } else if (allowedHeaders.join) { allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string } if (allowedHeaders && allowedHeaders.length) { headers.push([{ key: 'Access-Control-Allow-Headers', value: allowedHeaders }]); } return headers; } function configureExposedHeaders(options) { var headers = options.exposedHeaders; if (!headers) { return null; } else if (headers.join) { headers = headers.join(','); // .headers is an array, so turn it into a string } if (headers && headers.length) { return { key: 'Access-Control-Expose-Headers', value: headers }; } return null; } function configureMaxAge(options) { var maxAge = options.maxAge && options.maxAge.toString(); if (maxAge && maxAge.length) { return { key: 'Access-Control-Max-Age', value: maxAge }; } return null; } function applyHeaders(headers, res) { for (var i = 0, n = headers.length; i < n; i++) { var header = headers[i]; if (header) { if (Array.isArray(header)) {  applyHeaders(header, res); } else if (header.key === 'Vary' && header.value) {  vary(res, header.value); } else if (header.value) {  res.setHeader(header.key, header.value); } } } } function cors(options, req, res, next) { var headers = [], method = req.method && req.method.toUpperCase && req.method.toUpperCase(); if (method === 'OPTIONS') { // preflight headers.push(configureOrigin(options, req)); headers.push(configureCredentials(options, req)); headers.push(configureMethods(options, req)); headers.push(configureAllowedHeaders(options, req)); headers.push(configureMaxAge(options, req)); headers.push(configureExposedHeaders(options, req)); applyHeaders(headers, res); if (options.preflightContinue ) { next(); } else { res.statusCode = options.optionsSuccessStatus || defaults.optionsSuccessStatus; res.end(); } } else { // actual response headers.push(configureOrigin(options, req)); headers.push(configureCredentials(options, req)); headers.push(configureExposedHeaders(options, req)); applyHeaders(headers, res); next(); } } function middlewareWrapper(o) { if (typeof o !== 'function') { o = assign({}, defaults, o); } // if options are static (either via defaults or custom options passed in), wrap in a function var optionsCallback = null; if (typeof o === 'function') { optionsCallback = o; } else { optionsCallback = function (req, cb) { cb(null, o); }; } return function corsMiddleware(req, res, next) { optionsCallback(req, function (err, options) { if (err) {  next(err); } else {  var originCallback = null;  if (options.origin && typeof options.origin === 'function') {  originCallback = options.origin;  } else if (options.origin) {  originCallback = function (origin, cb) {  cb(null, options.origin);  };  }  if (originCallback) {  originCallback(req.headers.origin, function (err2, origin) {  if (err2 || !origin) {  next(err2);  } else {  var corsOptions = Object.create(options);  corsOptions.origin = origin;  cors(corsOptions, req, res, next);  }  });  } else {  next();  } } }); }; } // can pass either an options hash, an options delegate, or nothing module.exports = middlewareWrapper;}());

The implementation principle is as follows:

Since the Access-Control-Allow-Origin attribute does not Allow you to set multiple domain names, we have to leave this path.

The most popular and effective method is to determine whether the Origin attribute value (req. Header. origin) in the request header is in our domain name White List. If it is in the whitelist, set Access-Control-Allow-Origin to the current Origin value, this satisfies the Single Domain Name requirements of Access-Control-Allow-Origin, and ensures that the current request is accessed. If the request is not in the whitelist, an error message is returned.

In this way, we will transfer the cross-origin request verification from the browser end to the server end. The verification of the Origin string is equivalent to the verification of the regular string. We can not only use array list verification, but also use regular expression matching.

The Code is as follows:

// Determine whether the origin is in the domain name whitelist. function isOriginAllowed (origin, allowedOrigin) {if (_. isArray (allowedOrigin) {for (let I = 0; I <allowedOrigin. length; I ++) {if (isOriginAllowed (origin, allowedOrigin [I]) {return true ;}return false ;} else if (_. isString (allowedOrigin) {return origin = allowedOrigin;} else if (allowedOrigin instanceof RegExp) {return allowedOrigin. test (origin);} else {return !! AllowedOrigin;} const ALLOW_ORIGIN = [// domain name whitelist '* .233.666.com', 'Hello .world.com ', 'Hello .. *. com ']; app. post ('A/B ', function (req, res, next) {let reqOrigin = req. headers. origin; // The origin attribute of the request Response Header // determine whether the request is in the domain name whitelist if (isOriginAllowed (reqOrigin, ALLOW_ORIGIN )) {// set CORS to the Origin value of the Request res. header ("Access-Control-Allow-Origin", reqOrigin); res. header ('access-Control-Allow-credentials', 'true'); // Your Business Code logic code... //...} else {res. send ({code:-2, msg: 'Illegal request '});}});

Oh yeah, perfect ~

Summary

The above is the sample code sharing for setting a multi-domain name whitelist for CORS requests in Node. js. For more information, see other related articles in the first PHP community!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.