扩展 OAuth2 Google Passport.js 策略以使用 JWT

Extending an OAuth2 Google Passport.js strategy to use JWT

我已经使用 JWT 设置了电子邮件和密码策略,并希望使用 Google OAuth 设置来扩展它,而不是使用 cookie。

现在,虽然两个 Google 身份验证路由工作正常,但正在我的用户集合中创建一个用户,我被发送回回调路由,当我为用户获取 undefined 时我尝试去 /api/current_user 路线。

这是我的代码:有什么想法吗?

index.js(入口点)

const express = require('express');
const http = require('http');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const app = express();
const mongoose = require('mongoose');
const cors = require('cors');
const config = require('./config');
const passport = require('passport');
mongoose.connect(process.env.cosmosConn || config.conn);
//App setup
app.use(morgan('combined'));
app.use(cors());
app.use(bodyParser.json({ type: '*/*' }));
app.use(passport.initialize());
app.use(passport.session());
const router = require('./router');
router(app);
//Server setup
const port = process.env.port || process.env.PORT || 3090;
const server = http.createServer(app);
server.listen(port);
console.log('Server listening on:', port);

router.js

const Authentication = require('./controllers/authentication');
const passport = require('passport');
const User = require('./models/user');
const PlotCast = require('./models/plotCast');
const requireAuth = passport.authenticate('jwt', { session: true });
const requireSignin = passport.authenticate('local', { session: true });
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
const passportService = require('./services/passport');

module.exports = function(app) {
    app.get('/',
        requireAuth,
        (req, res) =>
        {
            res.send({
                message: `Welcome to Trellis, ${req.user.email}! Here's what's going on with your plots:`
            });
        });
    app.post('/signin', requireSignin, Authentication.signin);
    app.post('/signup', Authentication.signup);
    app.post('/confirmation', Authentication.confirmation);
    app.post('/resend', Authentication.resend);
    app.post('/verify-email', Authentication.verifyEmail);
    app.post('/resend-verify-code', Authentication.resend);
    app.post('/reset-password', Authentication.resetPassword);
    app.post('/reset-password/verify', Authentication.verifyResetPassword);
    app.post('/reset-password/new', Authentication.resetPasswordNew);
    app.get('/plots',
        requireAuth,
        async (req, res) =>
        {
            const user = await User.findOne({ email: req.user.email }).lean()
            const company = user.company;
            const plotcast = await PlotCast.find({ owner: company }).lean();
            if (!plotcast) { throw new Error('Plot Casts not found') }
            else {res.send(plotcast); }
        });
    app.get(
        '/auth/google',
        passport.authenticate('google', {
        scope: ['profile', 'email']
    })
    );
    app.get('/auth/google/callback', passport.authenticate('google'));
    app.get('/api/current_user',(req, res) =>
    {
        console.log(req);
        res.send(req.user);
    })

    app.get('/api/logout', (req, res) =>
    {
        req.logout();
        res.send(req.user);
    })
};

passport.js

const passport = require('passport');
const User = require('../models/user');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const config = require('../config');

const localOptions = { usernameField: 'email' };
const localLogin = new LocalStrategy(localOptions,
    async (email, password, done) =>{
        const existingUser = await User.findOne({ email: email })
        if (!existingUser) { return done(null, false); }
        const passwordMatch = await existingUser.comparePassword(password);
        if (!passwordMatch) { return done(null, false); }
        return done(null, user);
});

const jwtOptions = {
    jwtFromRequest: ExtractJwt.fromHeader('authorization'),
    secretOrKey:  config.secret
};

const jwtLogin = new JwtStrategy(jwtOptions,
    async (payload, done) =>
    {
        try
        {
            const user = await User.findById(payload.sub);
            if (user)
            {
                done(null, user);
            } else
            {
                done(null, false);
            }
        }
        catch (e)
        {
            return done(e, false);
        }
});

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

passport.deserializeUser(async (id, done) =>
{
    const user = await User.findById(id)
    if(user){ done(null, user); }
});

passport.use(new GoogleStrategy(
    {
        clientID: config.googleClientID,
        clientSecret: config.googleClientSecret,
        callbackURL: '/auth/google/callback',
        proxy: true
    }, async (accessToken, refreshToken, profile, done) =>
    {
        const existingUser = User.findOne({ googleId: profile.id })
        if (existingUser)
        {
            done(null, existingUser)
        } else
        {
            const user = await new User({ googleId: profile.id }).save()
            done(null, user);
        }
    }
));

passport.use(jwtLogin);
passport.use(localLogin);

编辑:Async/Await

的重构代码

一旦 Google 命中您的回调路由,您必须生成令牌并将其发送给用户。您可能希望将用户 (res.redirect) 重定向到处理令牌交换的新路由。

换句话说,您可能希望在 Google 回调函数本身内部实现此逻辑:

app.get( '/auth/google/callback',
        passport.authenticate('google', {
            //successRedirect: '/',
            failureRedirect: '/'
            , session: false
        }),
        function(req, res) {
            var token = TokenService.encode(req.user);
            res.redirect("/api?token=" + token);
        });