CORS 교차 도메인 요청에서 다중 도메인 이름 화이트리스트를 설정하기 위한 Node.js의 샘플 코드 공유

黄舟
풀어 주다: 2017-03-28 14:34:18
원래의
2705명이 탐색했습니다.

이 글에서는 주로 Node.js CORS 크로스 도메인 요청에서 다중 도메인 이름 화이트리스트를 설정하는 방법을 샘플 코드를 통해 자세히 소개하고 있습니다. 그것은 모든 사람에게 유용할 것이라고 믿습니다. 필요한 친구는 아래를 살펴볼 수 있습니다.

CORS

CORS라고 하면 프론트엔드는 다들 잘 아실 거라 생각해서 여기서는 자세히 설명하지 않겠습니다. 자세한 내용은 이 기사를 읽어보세요.

CORS는 주로 인터페이스 액세스를 허용하는 도메인 이름에 대한 응답 헤더의 Access-Control-Allow-Origin 속성을 구성합니다. 가장 일반적인 설정은

res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true'); // 允许服务器端发送Cookie数据
로그인 후 복사

입니다. 그러나 이 설정은 가장 단순하고 조야하며 가장 안전하지도 않습니다. 이는 인터페이스가 모든 도메인 이름이 도메인 간 요청을 할 수 있도록 허용한다는 의미입니다. 그러나 일반적인 실제 비즈니스에서는 인터페이스가 전체가 아닌 하나 또는 소수의 웹사이트에만 도메인 간 요청 권한을 허용하는 것으로 예상됩니다.

그래서 똑똑한 분들은 여러 도메인 이름을 화이트리스트에 추가하는 것이 쉽지 않을까요? 그냥 일반적인 규칙만 작성하면 된다고 생각하실 것입니다. 그래도 작동하지 않으면 Access-Control-Allow-Origin 속성을 쉼표로 구분된 여러 도메인 이름에 직접 구성하는 것이 더 좋지 않을까요?

이렇게:

아아아아

이러한 글쓰기 방식은 유효하지 않다는 점을 말씀드리게 되어 죄송합니다. Node.js에서는 res 응답 헤더의 Access-Control-Allow-Origin 속성이 (*) 이외의 정규식과 일치할 수 없으며 도메인 이름을 쉼표로 구분할 수 없습니다. 즉, Access-Control-Allow-Origin의 속성 값은 단일 특정 도메인 이름 문자열 또는 (*)에만 설정되도록 허용됩니다.

여러 도메인 이름을 허용하고 안전하지 않은 * 와일드카드 를 사용하고 싶지 않기 때문에 여러 도메인 이름 화이트리스트에 대해 CORS를 구성할 수 없다는 것이 사실입니까?

여러 도메인 이름 화이트리스트가 있는 CORS는 실제로 달성 가능합니다. 나라를 구하기 위한 약간의 반전이 있을 뿐입니다.

다중 도메인 화이트리스트의 CORS 구현 원칙

구체적인 원칙은 cors 라이브러리의 핵심 코드를 참조하세요.

res.header('Access-Control-Allow-Origin', '*.666.com'); 

// 或者如下
res.header('Access-Control-Allow-Origin', 'a.666.com,b.666.com,c.666.com');
로그인 후 복사

구현 원칙은 다음과 같습니다.

Access-Control-Allow-Origin 속성에서 여러 도메인 이름을 설정할 수 없음을 분명히 하였으므로, 우리는 이 길을 포기해야 합니다.

가장 널리 사용되고 효과적인 방법은 요청된 헤더의 Origin 속성 값(req.header.origin)이 도메인 이름 허용 목록에 있는지 서버 측에서 확인하는 것입니다. 화이트리스트에 있는 경우 Access-Control-Allow-Origin을 현재 Origin 값으로 설정합니다. 이는 Access-Control-Allow-Origin의 단일 도메인 이름 요구 사항을 충족하고 현재 요청이 있는 경우 액세스되도록 합니다. 화이트리스트에 없으면 오류 메시지가 반환됩니다.

이런 방식으로 교차 도메인 요청 확인을 브라우저에서 서버로 전송합니다. 원본 문자열 확인은 일반 문자열 확인과 동일하게 됩니다. 배열 목록 확인을 사용할 수 있을 뿐만 아니라 일반 일치도 사용할 수 있습니다.

구체 코드는 다음과 같습니다.

(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 === &#39;*&#39;) {
 // allow any origin
 headers.push([{
 key: &#39;Access-Control-Allow-Origin&#39;,
 value: &#39;*&#39;
 }]);
 } else if (isString(options.origin)) {
 // fixed origin
 headers.push([{
 key: &#39;Access-Control-Allow-Origin&#39;,
 value: options.origin
 }]);
 headers.push([{
 key: &#39;Vary&#39;,
 value: &#39;Origin&#39;
 }]);
 } else {
 isAllowed = isOriginAllowed(requestOrigin, options.origin);
 // reflect origin
 headers.push([{
 key: &#39;Access-Control-Allow-Origin&#39;,
 value: isAllowed ? requestOrigin : false
 }]);
 headers.push([{
 key: &#39;Vary&#39;,
 value: &#39;Origin&#39;
 }]);
 }

 return headers;
 }

 function configureMethods(options) {
 var methods = options.methods;
 if (methods.join) {
 methods = options.methods.join(&#39;,&#39;); // .methods is an array, so turn it into a string
 }
 return {
 key: &#39;Access-Control-Allow-Methods&#39;,
 value: methods
 };
 }

 function configureCredentials(options) {
 if (options.credentials === true) {
 return {
 key: &#39;Access-Control-Allow-Credentials&#39;,
 value: &#39;true&#39;
 };
 }
 return null;
 }

 function configureAllowedHeaders(options, req) {
 var allowedHeaders = options.allowedHeaders || options.headers;
 var headers = [];

 if (!allowedHeaders) {
 allowedHeaders = req.headers[&#39;access-control-request-headers&#39;]; // .headers wasn&#39;t specified, so reflect the request headers
 headers.push([{
 key: &#39;Vary&#39;,
 value: &#39;Access-Control-Request-Headers&#39;
 }]);
 } else if (allowedHeaders.join) {
 allowedHeaders = allowedHeaders.join(&#39;,&#39;); // .headers is an array, so turn it into a string
 }
 if (allowedHeaders && allowedHeaders.length) {
 headers.push([{
 key: &#39;Access-Control-Allow-Headers&#39;,
 value: allowedHeaders
 }]);
 }

 return headers;
 }

 function configureExposedHeaders(options) {
 var headers = options.exposedHeaders;
 if (!headers) {
 return null;
 } else if (headers.join) {
 headers = headers.join(&#39;,&#39;); // .headers is an array, so turn it into a string
 }
 if (headers && headers.length) {
 return {
 key: &#39;Access-Control-Expose-Headers&#39;,
 value: headers
 };
 }
 return null;
 }

 function configureMaxAge(options) {
 var maxAge = options.maxAge && options.maxAge.toString();
 if (maxAge && maxAge.length) {
 return {
 key: &#39;Access-Control-Max-Age&#39;,
 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 === &#39;Vary&#39; && 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 === &#39;OPTIONS&#39;) {
 // 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 !== &#39;function&#39;) {
 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 === &#39;function&#39;) {
 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 === &#39;function&#39;) {
  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;

}());
로그인 후 복사

아 맞네요~

요약

위 내용은 CORS 교차 도메인 요청에서 다중 도메인 이름 화이트리스트를 설정하기 위한 Node.js의 샘플 코드 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!