扩展 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);
});
我已经使用 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);
});