Maison > Article > interface Web > Exemple de partage de code pour Node.js afin de configurer une liste blanche de noms multi-domaines dans les requêtes inter-domaines CORS
Cet article présente principalement la méthode de Node.js configuration d'une liste blanche de noms multi-domaines dans les requêtes inter-domaines CORS L'article le présente en détail à travers un exemple de code I. Je pense que cela sera utile à tout le monde. Il a une certaine valeur de référence. Les amis qui en ont besoin peuvent jeter un œil ci-dessous.
CORS
En parlant de CORS, je pense que tout le monde connaît le front-end, donc je n'entrerai pas dans les détails ici. pouvez lire cet article pour plus de détails.
CORS configure principalement l'attribut Access-Control-Allow-Origin dans l'en-tête Response sur le nom de domaine auquel vous autorisez l'interface à accéder. Les paramètres les plus courants sont :
res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Credentials', 'true'); // 允许服务器端发送Cookie数据
Cependant, ce paramètre est le plus simple et le plus grossier, et c'est aussi le moins sûr. Cela signifie que l'interface permet à tous les noms de domaine de lui faire des requêtes inter-domaines. Cependant, dans les affaires réelles en général, on s'attend à ce que l'interface permette uniquement d'ouvrir des autorisations de requête inter-domaines à un ou quelques sites Web, pas à tous.
Alors, vous les gens intelligents, vous devez vous demander : n'est-il pas facile de mettre plusieurs noms de domaine sur liste blanche ? Il suffit d'écrire une règle régulière ? Si cela ne fonctionne pas, ne serait-il pas préférable de configurer directement l'attribut Access-Control-Allow-Origin sur plusieurs noms de domaine séparés par des virgules ?
Comme ceci :
res.header('Access-Control-Allow-Origin', '*.666.com'); // 或者如下 res.header('Access-Control-Allow-Origin', 'a.666.com,b.666.com,c.666.com');
J'ai le regret de vous dire que cette façon d'écrire est invalide. Dans Node.js, l'attribut Access-Control-Allow-Origin dans l'en-tête de réponse res ne peut pas correspondre aux expressions régulières autres que (*), et les noms de domaine ne peuvent pas être séparés par des virgules. En d'autres termes, la valeur de l'attribut Access-Control-Allow-Origin ne peut être définie que sur un seul nom de domaine spécifique chaîne ou (*).
Puisque nous souhaitons autoriser plusieurs noms de domaine et ne sommes pas disposés à utiliser le caractère générique non sécurisé * , est-il vraiment impossible de configurer CORS pour la liste blanche de plusieurs noms de domaine ?
CORS avec plusieurs listes blanches de noms de domaine est en effet réalisable. Il y a juste un petit truc pour sauver le pays.
Principe d'implémentation CORS de la liste blanche multi-domaines
Pour les principes spécifiques, veuillez vous référer au code de base de la bibliothèque cors :
(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; }());
Le principe de mise en œuvre est le suivant :
Puisque l'attribut Access-Control-Allow-Origin a précisé que plusieurs noms de domaine ne peuvent pas être défini, alors nous devons abandonner ce chemin.
La méthode la plus populaire et la plus efficace consiste à déterminer côté serveur si la valeur de l'attribut Origin (req.header.origin) dans l'en-tête demandé figure dans notre liste blanche de noms de domaine. S'il figure dans la liste blanche, nous définissons Access-Control-Allow-Origin sur la valeur Origin actuelle, qui répond à l'exigence de nom de domaine unique d'Access-Control-Allow-Origin et garantit que la demande actuelle est accédée si c'est le cas ; n'est pas dans la liste blanche, un message d'erreur sera renvoyé.
De cette manière, nous transférons la vérification des requêtes cross-domaines du navigateur vers le serveur. La vérification de la chaîne Origin devient équivalente à la vérification d'une chaîne normale. Nous pouvons non seulement utiliser la vérification de tableau liste, mais également utiliser la correspondance régulière.
Le code spécifique est le suivant :
// 判断origin是否在域名白名单列表中 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 = [ // 域名白名单 '*.233.666.com', 'hello.world.com', 'hello..*.com' ]; app.post('a/b', function (req, res, next) { let reqOrigin = req.headers.origin; // request响应头的origin属性 // 判断请求是否在域名白名单内 if(isOriginAllowed(reqOrigin, ALLOW_ORIGIN)) { // 设置CORS为请求的Origin值 res.header("Access-Control-Allow-Origin", reqOrigin); res.header('Access-Control-Allow-Credentials', 'true'); // 你的业务代码逻辑代码 ... // ... } else { res.send({ code: -2, msg: '非法请求' }); } });
Oh ouais, c'est parfait~
Résumé
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!