NodeJS js中的本地和Google策略:序列化用户时的问题

jaxagkaj  于 11个月前  发布在  Node.js
关注(0)|答案(2)|浏览(112)

我一直在试图理解为什么我不能让一个用户在认证后保持登录,即使认证本身是工作的。
通过尝试解决这个问题,我终于找到了问题所在。
问题如下:我有两个不同的passport策略,所以我序列化和重新序列化用户两次。如果我先用本地策略序列化用户,本地策略会起作用,但Google的不会。反之亦然。
我在app.js中添加了一条注解来强调这个问题。
这是文件
app.js

const   express           = require("express"),
        mongoose          = require("mongoose"),
        bodyParser        = require("body-parser"),
        cookieSession     = require("cookie-session"),
        localStrategy     = require("passport-local"),
        passport          = require("passport");

const LocalUser = require("./models/localuser");

const keys = require("./config/keys"); // requiring keys

const authRoutes = require("./routes/auth"); // requiring auth routes
const mainRoutes = require("./routes/main");

//Initialize express app
const app = express();

mongoose.connect("mongodb://localhost/thoughtApp"); // connectiong database

app.use(express.static(__dirname + "/public"));
app.set("view engine", "ejs"); 
app.use(bodyParser.urlencoded({extended: true}));

app.use(cookieSession({
    maxAge: 24 * 60 * 60 * 1000,
    keys: [keys.session.cookieKey]
}));

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

passport.use(new localStrategy(LocalUser.authenticate()));
passport.serializeUser(LocalUser.serializeUser());
passport.deserializeUser(LocalUser.deserializeUser());

app.use(function(req, res, next){
    res.locals.user = req.user;
    next();
});

app.use("/", mainRoutes); //main routes
app.use("/auth", authRoutes); // setup auth routes

const passportSetup = require("./config/passport-setup"); /// THIS IS THE ISSUE

// IF BeFORE LINE 33 ( passport.use(new localStrategy(LocalUser.authenticate()));, GOOGLE LOGIN WORKS BUT LOCAL DOESNT; IF AFTER, LOCAL WORKS BUT GOOGE DOESN'T; PROBABLY DUE TO SERIALIZE AND DESARIALIZE BEING USED ALREADY

app.listen(process.env.PORT || 3000, () => {
    console.log("Server started.")
});

字符串
auth.js(auth routes)

const router = require("express").Router();
const passport = require("passport");

const LocalUser = require("../models/localuser");

const authCheck = function (req, res, next) {
    if (!req.user) {
        next();
    } else {
        res.redirect("/");
    }
};
//login
router.get("/login", authCheck, (req, res) => {
    res.render("login", {user: req.user});
});

router.post("/login", passport.authenticate("local", {
    successRedirect: "/",
    failureRedirect: "/login"
}), (req, res) => {

})
// logout
router.get("/logout", (req, res) => {
    //handle with passport
    req.logout();
    res.redirect("/");
});

//register
router.get("/signup", authCheck, (req, res) => {
    res.render("signup", {user: req.user});
});

router.post("/signup", (req, res) => {
    LocalUser.register(new LocalUser({username: req.body.username}), req.body.password, (err, user) => {
        if (err) {
            console.log(err);
            res.redirect("/auth/signup")
        }  
        passport.authenticate("local")(req, res, () => {
            console.log(user)
            res.redirect("/");
        })
    })

})
// google auth

router.get("/google", authCheck, passport.authenticate("google", {
    scope: ["profile"]
})) 
    //goes to google consent screen

    // callback for google to redirect to
router.get("/google/redirect", passport.authenticate("google"), (req, res) => {
    res.redirect("/profile");
});

module.exports = router;


passport-setup.js(google strategy setup)

const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20");
const keys = require("./keys");

const User = require("../models/user")

passport.serializeUser((user, done) => {
    done(null, user.id);
});

passport.deserializeUser((id, done) => {
    User.findById(id).then((user) => {
        done(null, user);
    });
});

passport.use(new GoogleStrategy({
    //options for the google strategy
    callbackURL: "/auth/google/redirect",
    clientID : keys.google.clientID,
    clientSecret : keys.google.clientSecret

    }, (accessToken, refreshToken, profile, done) => {
    //passport callback function
    // check if user exists already
    User.findOne({googleID: profile.id}).then((currentUser) => {
        if (currentUser) {
            console.log("user is: " + currentUser);
            done(null, currentUser);
        } else {
            new User({
                username: profile.displayName,
                googleID: profile.id
            }).save().then((newUser) => {
                console.log("new user created: " + newUser);
                done(null, newUser);
            })
        }
    })

    })
)


localuser.js

const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");

const localUserSchema = new mongoose.Schema({
    username: String,
    password: String
});

localUserSchema.plugin(passportLocalMongoose);

module.exports = mongoose.model("localUser", localUserSchema);


我该怎么解决这个问题?

bxpogfeg

bxpogfeg1#

所以我一直在努力与同样的,我不知道如果你找到了解决方案,但我偶然发现了这个链接,
Linking all accounts together
因此,基本上,首先需要检查请求中是否存在req.user,如果存在,则添加要序列化的字段并调用done(null,newUser)
这个应该可以
我希望我说得够清楚了

vyu0f0g1

vyu0f0g12#

这是一个非常古老的主题,但由于仍然没有答案,我希望它能帮助一些人。
我是通过使用provider来进行用户身份验证的(在我的例子中是GoogleStrategy)。当使用第三方服务(如Google或Twitter)进行身份验证时,通常会提供用户个人资料信息。
See reference to the official Passport.js documentation

config/passport.ts

passport.serializeUser((user: IUserDoc | IGoogleUser, callback) => {
  const userSessionInfo = {
    id:
      user.provider === "google"
        ? (user as IGoogleUser).googleId
        : (user as IUserDoc).id,
    provider: user.provider,
  };
  callback(null, userSessionInfo);
});

passport.deserializeUser(async (user: any, done) => {
  try {
    const googleProvider = user.provider === "google";
    const foundUser: any = googleProvider
      ? await GoogleUser.findById(user.id)
      : await User.findById(user.id);

    if (!foundUser) {
      return done(null, null);
    }

    const userWithoutPassword = {
      id: foundUser._id,
      firstName: foundUser.firstName,
      lastName: foundUser.lastName,
      birthDate: foundUser.birthDate,
      email: foundUser.email,
      image: foundUser.image,
    } as IUserWithoutPassword;

    done(null, googleProvider ? user : userWithoutPassword);
  } catch (error) {
    done(error, false);
  }
});

// Local strategy
passport.use(
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
    },
    async (email, password, done) => {
      try {
        const user = await User.findOne({ email });

        if (!user) {
          return done(null, false, {
            message: messages.userNotExists,
          });
        }

        const isMatch = await user.isPasswordMatch(password);

        if (!isMatch) {
          return done(null, false, {
            message: messages.incorrectCredentials,
          });
        }

        done(null, user);
      } catch (error) {
        done(error, false);
      }
    }
  )
);

// Google strategy
passport.use(
  new GoogleStrategy(
    {
      clientID: config.google.client,
      clientSecret: config.google.secret,
      callbackURL: "/api/user/google/redirect",
      scope: ["profile", "emails"],
    },
    async (
      accessToken: string,
      refreshToken: string,
      profile: Profile,
      callback: (
        err?: string | Error | null | undefined,
        user?: Express.User | undefined,
        info?: any
      ) => void
    ) => {
      try {
        const existingUser = await GoogleUser.findOne({ googleId: profile.id });

        if (existingUser) {
          return callback(null, existingUser);
        }

        const newUser = await GoogleUser.create({
          googleId: profile.id,
          firstName: profile.name?.givenName,
          lastName: profile.name?.familyName,
          email: profile.emails?.[0].value,
          displayName: profile.displayName,
          image: profile.photos?.[0].value,
          provider: profile.provider,
        });

        return callback(null, newUser);
      } catch (error: any) {
        return callback(error.message);
      }
    }
  )
);

字符串

相关问题