首页 > 解决方案 > 尝试结合 PassportJS 和 ReCAPTCHA V2 时出错。“SyntaxError:JSON.parse:JSON 数据第 1 行第 1 列的意外字符”

问题描述

设置我的第一个 ExpressJS 投资组合页面,用户使用 PassportJS 登录。我想将来自 Google 的 ReCAPTCHA V2 添加到登录过程中,但是当我结合 Passport 和 ReCAPTCHA 时出现错误。

错误:SyntaxError:JSON.parse:JSON 数据的第 1 行第 1 列出现意外字符

我相信错误来自我在 POST 部分中设置 return next() 的方式,但我不知道为什么。我尝试了一些不同的配置,谷歌搜索无济于事。

如果我删除 POST 部分中的 passportJS 代码,则 ReCAPTCHA V2 代码有效。我肯定错过了一些简单的东西,但我不知道如何让它们一起工作。任何帮助表示赞赏。

注意:为了安全起见,我删除了我的两个 ReCAPTCHA V2密钥(站点密钥和密钥),它们必须被 Google ReCAPTCHA Version 2中的工作密钥替换。

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const passport = require('passport');
const mongoose = require('mongoose');
const LocalStrategy = require('passport-local').Strategy;

const app = express();

mongoose.connect('mongodb://localhost/MyDatabase', { useNewUrlParser: true, useUnifiedTopology: true });

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(passport.initialize());
app.use(passport.session());

passport.use(new LocalStrategy(
  function (username, password, done) {
    UserDetails.findOne({
      username: username
    }, function (err, user) {
      if (err) {
        return done(err);
      }

      if (!user) {
        return done(null, false);
      }

      if (user.password != password) {
        return done(null, false);
      }
      return done(null, user);
    });
  }
));

passport.serializeUser(function (user, cb) {
  cb(null, user.id);
});

passport.deserializeUser(function (id, cb) {
  User.findById(id, function (err, user) {
    cb(err, user);
  });
});

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});


const Schema = mongoose.Schema;
const UserDetail = new Schema({
  username: String,
  password: String
});
const UserDetails = mongoose.model('userInfo', UserDetail, 'userInfo');


app.post('/', (req, res) => {
  if (
    req.body.captcha === undefined ||
    req.body.captcha === '' ||
    req.body.captcha === null

  ) {
    return res.json({ "success": false, "msg": "Please select captcha" }); // If no CAPTCHA is selected / checkbox not checked
  }

  // secret key
  const secretKey = 'INSERT SECRET KEY'; // You need to add a secret key from Google ReCAPTCHA V2

  // verify URL
  const verifyUrl = `https://google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body.captcha}&remoteip=${req.connection.remoteAddress}`;

  // make request to verify url
  request(verifyUrl, (err, response, body) => {
    body = JSON.parse(body);
    console.log("parsed body: ", body);
    // if not successful
    if (body.success !== undefined && !body.success) {
      console.log("Request verifyUrl failed");
      return res.json({ "success": false, "msg": "Failed captcha vericiation" }); // if can't connect to Google and verify CAPTCHA
    }

    // line below works if passport code and next() is removed
    // return res.json({ "success": true, "msg": "captcha passed!" }); // Connected to Google and verified CAPTCHA
  });
  return next(); // Is the error coming from this?
},
  passport.authenticate('local'),
  function (req, res) {
    console.log("Passport function was called ...");
    // If this function gets called, authentication was successful.
    // `req.user` contains the authenticated user.
    res.redirect('/success');
  });

// ####################### PASSPORT


// ######################### PASSPORT END

app.listen(3000, () => {
  console.log("SERVER STARTED on port 3000")
});

我的 HTML 文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <script src="//www.google.com/recaptcha/api.js"></script>
    <title>Recaptcha and Passport Test</title>
</head>

<body>
    <div class="container">
        <h1>Subscribe</h1>
        <form id="subscribeForm">
            <div class="form-group">
                <label for="username">Username</label>
                <input type="text" name="username" class="form-control" id="username">
            </div>
            <div class="form-group">
                <label for="password">Password</label>
                <input type="password" name="password" class="form-control" id="password">
            </div>
            <div class="form-group">
                <div class="g-recaptcha" data-sitekey="SITE KEY GOES HERE"></div>
            </div>
            <input type="submit" value="submit" class="btn btn-primary">
        </form>
    </div>


    <script>
        document.getElementById('subscribeForm').addEventListener('submit', submitForm);

        function submitForm(e) {
            e.preventDefault();
            
            const username = document.querySelector('#username').value;
            const password = document.querySelector('#password').value;
            const captcha = document.querySelector('#g-recaptcha-response').value;

            fetch('/', {
                method: 'POST',
                headers: {
                    'Accept': 'application/json, text/plain, */*',
                    'Content-type': 'application/json'
                },
                body: JSON.stringify({username: username, password: password, captcha: captcha})
            })
            .then((res) => res.json())
            .then((data) => {
                console.log("Fetch data: ", data);
            })
        }
    </script>
</body>

</html>

要查看它运行时没有错误,请删除 POST 部分中的 passport.authenticate 代码,以及它上面的 return next()。还取消注释 next() 上方的 return res.json 成功行。

标签: javascriptexpresspassport.jsrecaptcha

解决方案


推荐阅读