将 fetch 与 Passport 一起使用会得到“请求的资源上不存在‘Access-Control-Allow-Origin’标头。”

Posted

技术标签:

【中文标题】将 fetch 与 Passport 一起使用会得到“请求的资源上不存在‘Access-Control-Allow-Origin’标头。”【英文标题】:Using fetch with Passport gets "No 'Access-Control-Allow-Origin' header is present on the requested resource." 【发布时间】:2020-12-26 05:52:26 【问题描述】:

我正在尝试在我的网站上放置一个按钮,让用户授权访问他的 YouTube 帐户。我正在使用 Passport 进行身份验证。我的代码使用 fetch 发送请求。当我点击按钮时,我得到:

访问获取 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fgooglecb&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth %2Fyoutube&client_id=...' (从 'http://localhost:3000/google' 重定向) “http://localhost:3000”已被 CORS 策略阻止:响应 预检请求未通过访问控制检查:否 请求中存在“Access-Control-Allow-Origin”标头 资源。如果不透明的响应满足您的需求,请设置请求的 模式为“no-cors”以获取禁用 CORS 的资源。

如果我对 /google 使用 href ,它可以工作。

app.js:

const appConfig = require('./config.js');
const cors = require('cors')
const express = require('express');
const passport = require('passport');
const path = require('path');
const YoutubeV3Strategy = require('passport-youtube-v3').Strategy;

const index = require('./routes/index');

const app = express();

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(cors());

app.use(passport.initialize());
app.use(passport.session());

passport.use(new YoutubeV3Strategy(
  clientID: appConfig.youtube.id,
  clientSecret: appConfig.youtube.secret,
  callbackURL: 'http://localhost:3000/googlecb',
  scope: ['https://www.googleapis.com/auth/youtube'],
,
function (accessToken, refreshToken, profile, cb) 
  const user = 
    accessToken: accessToken,
    refreshToken: refreshToken,
    profile: profile,
  ;
  return cb(null, user);
));

passport.serializeUser((user, cb) => 
  cb(null, user);
);

passport.deserializeUser((obj, cb) => 
  cb(null, obj);
);

app.use('/', index);

app.use(function(req, res, next) 
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
);

app.use(function(err, req, res, next) 
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : ;
  res.status(err.status || 500);
  res.render('error');
);

module.exports = app;

index.js:

const express = require('express');
const passport = require('passport');

const router = express.Router();

router.get('/', function(req, res, next) 
  res.render('index');
);

router.get('/google', async (req, res) => 
  passport.authenticate('youtube')(req, res, () => res.send('ok'));
);

router.get('/googlecb', passport.authenticate('youtube'), async (req, res) => 
  const name = req.user.profile.displayName;
  console.log('googlecb name: ' + name);
  return res.send(req.user);
);

module.exports = router;

index.ejs:

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p><button id="auth" onclick="go()">Authorize</button><p>
    <p><a href="/google">Authorize</a><p>
    <script> 
async function go() 
  console.log('go');
  await fetch('/google',
    
      method: 'GET',
      headers: 
        'Content-Type': 'application/json',
      ,
    ,
  )
  .then(response => 
    console.log('response');
    return response.json();
  )
  .then(data => 
    console.log('data');
  );

    </script>
  </body>
</html>

【问题讨论】:

在错误消息Access to fetch at 'https:...' (redirected from 'http://localhost:3000/google')中,您省略的网址是什么? 无论您省略了什么 URL,该 URL 处的服务器都需要启用 CORS。如果您将前端请求重定向到该 URL,那么仅启用 CORS 支持您自己的 http://localhost:3000/ 服务器是不够的。相反,省略的 URL 处的服务器也需要启用 CORS。而且您无法像现在这样在两者之间使用您自己的http://localhost:3000/ 服务器来解决这个问题——因为您现在设置的内容导致您的前端 javascript 代码直接从服务器在省略的 URL 处接收响应,而不是来自您的 http://localhost:3000/ 服务器。 可能重复:***.com/questions/48177354/…***.com/questions/49814440/…***.com/questions/45487449/…***.com/questions/50317575/… 可能重复:***.com/questions/63799912/…***.com/questions/63799074/… 【参考方案1】:

好的,这是 Passport 的一个未解决问题:

https://github.com/jaredhanson/passport/issues/582#issuecomment-506283986

我应该使用 href 而不是 fetch。

可能重复

Cors error when sending request from React frontend to Google Oauth PassportJS on backend

【讨论】:

以上是关于将 fetch 与 Passport 一起使用会得到“请求的资源上不存在‘Access-Control-Allow-Origin’标头。”的主要内容,如果未能解决你的问题,请参考以下文章

将 Laravel Passport 与移动应用程序一起使用

将 fetch 与变量一起使用 [重复]

如何将 window.fetch() 与 httpOnly cookie 或基本身份验证一起使用

将 Fetch 与授权标头和 CORS 一起使用

将 fetch 与 async/await 一起使用会返回 [object Object]

将 fetch 与浏览器 cookie 一起使用