Node+react 应用程序中使用护照进行 facebook 身份验证时出现 CORS 错误

saw*_*wim 5 node.js facebook-oauth reactjs passport-facebook passport.js

我正在使用 Node 开发简单的 Web 应用程序,并使用 Facebook 身份验证进行反应。我还遵循了一些有关该主题的教程,但在这些实现中,客户端和后端位于同一服务器上。在这里,我的后端服务器在 localhost:5000 上运行,并在 localhost:3000 上运行应用程序。在react package.json中有到后端的代理,因此客户端知道如何调用api。

\n\n

当我单击“使用 Facebook 登录”按钮时,我将重定向到 Facebook 页面,在其中我授权应用程序并接收我的客户端应用程序配置文件 ID 和其他请求的用户信息。然而,当我将用户信息发送到后端服务器时,我可以在控制台中看到以下错误:

\n\n
\n

跨源请求被阻止:同源策略不允许读取远程资源https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fapi%2Fauth%2Ffacebook% 2Fcallback&client_id=1617633901657669。(原因:CORS 标头 \xe2\x80\x98Access-Control-Allow-Origin\xe2\x80\x99 丢失)。

\n
\n\n

下面你可以看到:

\n\n
\n

类型错误:尝试获取资源时出现网络错误。\n [了解更多]

\n
\n\n

Facebook 应用程序设置:

\n\n
    \n
  1. 在此输入图像描述
  2. \n
  3. 在此输入图像描述
  4. \n
  5. 在此输入图像描述
  6. \n
\n\n

OAuth 路由器:

\n\n
const router = require(\'express\').Router();\nconst passport = require(\'../config/facebook-passport\');\n\nrouter.get(\'/facebook\', passport.authenticate(\'facebook\'));\n\nrouter.get(\'/facebook/callback\',\n    passport.authenticate(\'facebook\', { failureRedirect: \'/login\' }),\n    function(req, res) {\n        console.log(\'Successful authentication, redirect home\');\n        res.redirect(\'/\');\n    });\n\nmodule.exports = router;\n
Run Code Online (Sandbox Code Playgroud)\n\n

护照脸书:

\n\n
const passport = require(\'passport\');\nconst FacebookStrategy = require(\'passport-facebook\').Strategy;\n\npassport.use(new FacebookStrategy({\n    clientID: process.env.CLIENTID,\n    clientSecret: process.env.CLIENTSECRET,\n    callbackURL: "/api/auth/facebook/callback"\n},\nfunction(accessToken, refreshToken, profile, done) {\n    console.log(accessToken, refreshToken, profile)\n}\n));\nmodule.exports = passport;\n
Run Code Online (Sandbox Code Playgroud)\n\n

应用程序.js:

\n\n
app.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(session({\n    secret: \'3cr3ts#tr\',\n    resave: true,\n    saveUninitialized: true\n}));\napp.use(passport.initialize());\napp.use(passport.session());\n\napp.use(\'/api/users\', users);\napp.use(\'/api/oauth\', oauth);\napp.get(\'/api/hello\', ensureAuthenticated, function(req, res, next) {\n    res.send({express: \'Hello there\'})\n});\n\napp.listen(5000);\n\nfunction ensureAuthenticated(req, res, next) {\n    if (req.isAuthenticated()) {\n        return next();\n    }\n    res.status(401);\n    res.send({express: "you need to authenticate"})\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

登录反应组件:

\n\n
import FacebookLogin from \'react-facebook-login\';\n\nclass Login extends Component {\n    sendFacebookResponse(response) {\n    fetch(`/api/oauth/facebook?${Object.keys(response).map(k => k+\'=\'+response[k]).join(\'&\')}`)\n    }\n\nrender() {\n    return (\n        <FacebookLogin\n            appId="1617633901657669"\n            autoLoad={true}\n            fields="name,email,picture"\n            callback={this.sendFacebookResponse} />\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的应用程序配置正确吗?如何消除 CORS 错误?任何帮助或建议将不胜感激。

\n

saw*_*wim 1

首先,我从Passport-facebook切换到Passport-facebook-token

然后我添加了2个护照策略。Facebook 用作身份验证提供者,jwt 则用于授权请求。

const FacebookStrategy = require('passport-facebook-token');
const passportJWT = require('passport-jwt');


passport.use(new FacebookStrategy({
    clientID: <FB CLIENT ID>,
    clientSecret: <FB CLIENT SECRET>
},
(token, refreshToken, profile, done) => {
    // here there should be code responsible for fetching user from database based on facebook profile, saving user if it doesn't exist yet etc.

    done(null, user);
}
));


// this will parse jwtPayload (sent as header; "Authorization: Bearer <JWT TOKEN>") into user object, which will be added to request objects in express router endpoints handlers 
passport.use('jwt', new passportJWT.Strategy({
            jwtFromRequest: passportJWT.ExtractJWT.fromAuthHeaderAsBearerToken(),
            secretOrKey: "secret salt"
        }, (jwtPayload, done) => {
            done(null, jwtPayload);
        }));
Run Code Online (Sandbox Code Playgroud)

然后我添加了用于用户身份验证的端点。Passport-facebook-token库期望获取从客户端应用程序发送的 facebook 访问令牌作为查询参数 access_token=FACEBOOK_ACCESS_TOKEN。通过fb成功授权后,可以生成jwt令牌,发送到客户端应用程序并用于请求授权。

const { sign } = require('jsonwebtoken');

router.get(
    '/facebook-token', 
    passport.authenticate('facebook-token', {session: false}), 
    (req, res, next) => {
        res
            .send({
                token: sign(req.user,  "secret salt" /* the same value that was used to configure jwt passport above */, {})                
            })   
    });
Run Code Online (Sandbox Code Playgroud)

现在用户应该经过身份验证,换句话说,应该在上面的端点中生成一个 jwt 令牌。下一个请求中的客户端应用程序应该添加授权标头,这在前面已经提到过。

端点可以通过 Passport 库提供的中间件函数来保护,在这种情况下,passport.authenticate('jwt', {session: false}) 返回一个使用 jwt 策略的函数。

router.get('/secured-endpoint', passport.authenticate('jwt', {session: false}), (req, res, next) => {
    res.send("hello world")

    // there is req.user object that can be used for user specific actions
});
Run Code Online (Sandbox Code Playgroud)