Local and Google strategy in passport.js: issue when serializing user

巧了我就是萌 提交于 2020-01-03 02:47:13

问题


I've been trying to understand why I couldn't keep an user logged in once authenticated even though authentication itself was working. I even posted a question here: Passport.js - Local strategy doesn't authenticate

By trying to fix the issue, I finally worked out what's wrong.

The issue is the following: I have two different passport strategy, so I am serializing and deserializing the user twice. If I serialize the user with the local strategy first, local strategy will work, but Google's won't. And vice versa.

I put a comment to highlight the problem in app.js.

Here's the files:

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);

How can I solve this?


回答1:


So I have been struggling with the same and I don't know if you found a solution but I stumbled upon this link,

Linking all accounts together

So basically, you first need to check is in the request is req.user exists, if so add the fields you want to serialize and call done(null,newUser)

This should do the trick,

I hope i was clear enough



来源:https://stackoverflow.com/questions/51597706/local-and-google-strategy-in-passport-js-issue-when-serializing-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!