Authored by 毕凯

增加 PC 微信登录

/**
* passport 验证策略注册
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 2016/5/31
*/
'use strict';
const passport = require('passport');
const WeixinStrategy = require('passport-weixin');
const config = require('../../config/common');
let siteUrl = config.siteUrl.indexOf('//') === 0 ? 'http:' + config.siteUrl : config.siteUrl;
/**
* wechat登录
*/
passport.use('wechat', new WeixinStrategy({
clientID: config.thirdLogin.wechat.appID,
clientSecret: config.thirdLogin.wechat.appSecret,
callbackURL: `${siteUrl}/passport/login/wechat/callback`,
requireState: true,
scope: 'snsapi_login'
}, function(accessToken, refreshToken, profile, done) {
done(null, profile);
}));
... ...
/**
* 登录
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
*/
'use strict';
const library = '../../../library';
const passport = require('passport');
const uuid = require('uuid');
const cookie = require(`${library}/cookie`);
const helpers = require(`${library}/helpers`);
const log = require(`${library}/logger`);
const config = require('../../../config/common');
const AuthHelper = require('../models/auth-helper');
const loginPage = `${config.siteUrl}/passport/login/index`;
// 第三方登录回调
function doPassportCallback(req, res, next, user) {
let shoppingKey = cookie.getShoppingKey(req);
let refer = req.cookies.refer;
if (refer) {
refer = decodeURI(req.cookies.refer);
} else {
refer = config.siteUrl;
}
if (/sign|login/.test(refer)) {
refer = config.siteUrl;
}
if (user.openId && user.nickname) {
let signinByOpenID;
if (user.sourceType === 'wechat') {
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
signinByOpenID = AuthHelper.signinByOpenID(user.nickname, user.openId, user.sourceType, shoppingKey);
} else {
signinByOpenID = AuthHelper.signinByOpenID(user.nickname, user.openId, user.sourceType, shoppingKey);
}
signinByOpenID.then((result) => {
if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line
return helpers.urlFormat('/passport/bind/index', {
openId: user.openId,
sourceType: user.sourceType,
refer: refer
});
} else if (result.code === 200 && result.data.uid) {
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return refer;
});
}
}).then((redirectTo) => {
return res.redirect(redirectTo);
}).catch(next);
} else {
res.redirect(loginPage);
}
}
const wechat = {
beforeLogin: (req, res, next) => {
let refer = req.query.refer;
if (!refer) {
refer = req.get('Referer');
}
refer && res.cookie('refer', encodeURI(refer), {
domain: 'yohobuy.com'
});
next();
},
login: (req, res, next) => {
return passport.authenticate('wechat', {
state: uuid.v4()
})(req, res, next);
},
callback: (req, res, next) => {
passport.authenticate('wechat', (err, user) => {
if (err) {
log.error(`wechat authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
}
let nickname = user._json.nickname || user.displayName;
let openId = user._json.unionid || user.id;
doPassportCallback(req, res, next, {
openId: openId,
nickname: nickname,
sourceType: 'wechat',
rawUser: user
});
})(req, res, next);
}
};
exports.wechat = wechat;
... ...
/**
* sub app channel
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
*/
'use strict';
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var passport = require('passport');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
helpers: require(`${global.library}/helpers`)
}));
require('./auth');
app.use(passport.initialize());
app.use(passport.session());
// router
app.use(require('./router'));
module.exports = app;
... ...
'use strict';
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const api = new API();
class Auth {
static signinByOpenID(nickname, openId, sourceType, shoppingKey) {
let param = {
nickname: nickname,
openId: openId,
source_type: sourceType, // esline-disable-line
method: 'app.passport.signinByOpenID',
shoppingKey: shoppingKey
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
return api.get('', sign.apiSign(param));
}
static profile(uid) {
let param = {
uid: uid,
method: 'app.passport.profile'
};
return api.get('', sign.apiSign(param));
}
static syncUserSession(uid, req, res) {
return Auth.profile(uid).then((userInfo) => {
let token = sign.makeToken(uid);
let data = userInfo.data;
if (data) {
let uidCookie = `${data.profile_name}::${data.uid}::${data.vip_info.title}::${token}`;
res.cookie('_UID', uidCookie, {
domain: 'yohobuy.com'
});
}
req.session._TOKEN = token; // esline-disable-line
req.session._LOGIN_UID = uid; // esline-disable-line
res.cookie('_TOKEN', token, {
domain: 'yohobuy.com'
}); // esline-disable-line
}).catch(console.log);
}
}
module.exports = Auth;
... ...
/**
* router of sub app channel
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
*/
'use strict';
const express = require('express');
const cRoot = './controllers';
const login = require(cRoot + '/login');
const router = express.Router(); // eslint-disable-line
router.get('/login/wechat', login.wechat.beforeLogin, login.wechat.login); // 登录
router.get('/login/wechat/callback', login.wechat.callback);
module.exports = router;
... ...
... ... @@ -48,6 +48,12 @@ module.exports = {
colorize: 'all',
prettyPrint: true
}
},
thirdLogin: {
wechat: {
appID: 'wx3ae21dcbb82ad672',
appSecret: 'e78afb2321e6a19085767e1a0f0d52c1'
}
}
};
... ...
... ... @@ -12,4 +12,5 @@ module.exports = app => {
app.use(require('./apps/channel')); // 频道页
app.use(require('./apps/activity')); // 专题活动等活动页面
app.use('/product', require('./apps/product')); // 商品相关页面
app.use('/passport', require('./apps/passport')); // 登录注册
};
... ...
... ... @@ -94,3 +94,7 @@ exports.webSign = (params) => {
return params.key === md5(md5(webPrivateKey) + params.uid);
};
exports.makeToken = (string) => {
return md5(md5(string + '#@!@#'));
};
... ...
... ... @@ -43,13 +43,13 @@
"moment": "^2.13.0",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
"passport": "^0.3.2",
"passport-weixin": "^0.1.0",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"uuid": "^2.0.2",
"winston": "^2.2.0",
"winston-daily-rotate-file": "^1.0.1",
"yoho-connect-memcached": "^1.0.3",
"yoho-express-session": "^1.0.2"
"winston-daily-rotate-file": "^1.0.1"
},
"devDependencies": {
"autoprefixer": "^6.3.6",
... ...