Merge branch 'feature/wechat-auth' into release/sale
Showing
14 changed files
with
272 additions
and
32 deletions
@@ -39,7 +39,9 @@ app.set('view engine', '.hbs'); | @@ -39,7 +39,9 @@ app.set('view engine', '.hbs'); | ||
39 | app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); | 39 | app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); |
40 | app.use(express.static(path.join(__dirname, 'public'))); | 40 | app.use(express.static(path.join(__dirname, 'public'))); |
41 | app.use(bodyParser.json()); | 41 | app.use(bodyParser.json()); |
42 | -app.use(bodyParser.urlencoded({extended: false})); | 42 | +app.use(bodyParser.urlencoded({ |
43 | + extended: false | ||
44 | +})); | ||
43 | app.use(cookieParser()); | 45 | app.use(cookieParser()); |
44 | app.use(session({ | 46 | app.use(session({ |
45 | proxy: true, | 47 | proxy: true, |
@@ -56,8 +58,8 @@ app.use(session({ | @@ -56,8 +58,8 @@ app.use(session({ | ||
56 | }, | 58 | }, |
57 | store: new MemcachedStore({ | 59 | store: new MemcachedStore({ |
58 | hosts: config.memcache.session, | 60 | hosts: config.memcache.session, |
59 | - prefix: 'qinsessionsession:', // 兼容 PHP SESSION | ||
60 | - key: 'yohobuy_session' // 兼容 PHP SESSION | 61 | + prefix: 'qinsessionsession:', // 兼容 PHP SESSION |
62 | + key: 'yohobuy_session' // 兼容 PHP SESSION | ||
61 | }) | 63 | }) |
62 | })); | 64 | })); |
63 | 65 |
apps/passport/auth.js
0 → 100644
1 | +/** | ||
2 | + * passport 验证策略注册 | ||
3 | + * @author: jiangfeng<jeff.jiang@yoho.cn> | ||
4 | + * @date: 2016/5/31 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | +const passport = require('passport'); | ||
9 | +const WeixinStrategy = require('passport-weixin-plus'); | ||
10 | + | ||
11 | +const config = require('../../config/common'); | ||
12 | + | ||
13 | +let siteUrl = config.siteUrl.indexOf('//') === 0 ? 'http:' + config.siteUrl : config.siteUrl; | ||
14 | + | ||
15 | +/** | ||
16 | + * wechat登录 | ||
17 | + */ | ||
18 | +passport.use(new WeixinStrategy({ | ||
19 | + authorizationURL: 'https://open.weixin.qq.com/connect/oauth2/authorize', | ||
20 | + tokenURL: 'https://api.weixin.qq.com/sns/oauth2/access_token', | ||
21 | + clientID: config.thirdLogin.wechat.appID, | ||
22 | + clientSecret: config.thirdLogin.wechat.appSecret, | ||
23 | + callbackURL: `${siteUrl}/passport/login/wechat/callback`, | ||
24 | + requireState: false, | ||
25 | + scope: 'snsapi_userinfo' | ||
26 | +}, (accessToken, refreshToken, profile, done) => { | ||
27 | + done(null, profile); | ||
28 | +})); |
apps/passport/controllers/login.js
0 → 100644
1 | +/** | ||
2 | + * 登录 | ||
3 | + * @author: Bi Kai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/09 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | + | ||
8 | +const library = '../../../library'; | ||
9 | +const passport = require('passport'); | ||
10 | +const cookie = require(`${library}/cookie`); | ||
11 | +const helpers = require(`${library}/helpers`); | ||
12 | +const log = require(`${library}/logger`); | ||
13 | +const config = require('../../../config/common'); | ||
14 | +const AuthHelper = require('../models/auth-helper'); | ||
15 | + | ||
16 | +const loginPage = `${config.siteUrl}/passport/login/index`; | ||
17 | + | ||
18 | +function doPassportCallback(openId, nickname, sourceType, req, res) { | ||
19 | + let shoppingKey = cookie.getShoppingKey(req); | ||
20 | + let refer = req.cookies.refer; | ||
21 | + | ||
22 | + if (refer) { | ||
23 | + refer = decodeURI(req.cookies.refer); | ||
24 | + } else { | ||
25 | + refer = `${config.siteUrl}/home`; | ||
26 | + } | ||
27 | + | ||
28 | + if (openId && nickname) { | ||
29 | + AuthHelper.signinByOpenID(nickname, openId, sourceType, shoppingKey).then((result) => { | ||
30 | + if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line | ||
31 | + return helpers.urlFormat('/passport/bind/index', { | ||
32 | + openId: openId, | ||
33 | + sourceType: sourceType, | ||
34 | + refer: refer | ||
35 | + }); | ||
36 | + } else if (result.code === 200 && result.data.uid) { | ||
37 | + return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => { | ||
38 | + return refer; | ||
39 | + }); | ||
40 | + } | ||
41 | + }).then((redirectTo) => { | ||
42 | + console.log('redirectTo=', redirectTo); | ||
43 | + return res.redirect(redirectTo); | ||
44 | + }).catch((e) => { | ||
45 | + log.error('频道页面渲染错误:' + JSON.stringify(e)); | ||
46 | + return res.send('error'); | ||
47 | + }); | ||
48 | + } | ||
49 | +} | ||
50 | + | ||
51 | +const wechat = { | ||
52 | + beforeLogin: (req, res, next) => { | ||
53 | + let refer = req.query.refer; | ||
54 | + | ||
55 | + if (!refer) { | ||
56 | + refer = req.get('Referer'); | ||
57 | + } | ||
58 | + refer && res.cookie('refer', encodeURI(refer)); | ||
59 | + next(); | ||
60 | + }, | ||
61 | + login: (req, res, next) => { | ||
62 | + return passport.authenticate('weixin')(req, res, next); | ||
63 | + }, | ||
64 | + callback: (req, res, next) => { | ||
65 | + passport.authenticate('weixin', (err, user) => { | ||
66 | + if (err) { | ||
67 | + log.error(`wechat authenticate error : ${JSON.stringify(err)}`); | ||
68 | + return res.redirect(loginPage); | ||
69 | + } | ||
70 | + let nickname = user.displayName || user._json.nickname; | ||
71 | + let openId = user.id || user._json.unionid; | ||
72 | + | ||
73 | + doPassportCallback(openId, nickname, 'wechat', req, res); | ||
74 | + })(req, res, next); | ||
75 | + } | ||
76 | +}; | ||
77 | + | ||
78 | +exports.wechat = wechat; |
apps/passport/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app channel | ||
3 | + * @author: Bi Kai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/09 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | +var express = require('express'), | ||
8 | + path = require('path'), | ||
9 | + hbs = require('express-handlebars'); | ||
10 | + | ||
11 | +var passport = require('passport'); | ||
12 | + | ||
13 | +var app = express(); | ||
14 | + | ||
15 | +// set view engin | ||
16 | +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | ||
17 | + | ||
18 | +app.on('mount', function(parent) { | ||
19 | + delete parent.locals.settings; // 不继承父 App 的设置 | ||
20 | + Object.assign(app.locals, parent.locals); | ||
21 | +}); | ||
22 | + | ||
23 | +app.set('views', path.join(__dirname, 'views/action')); | ||
24 | +app.engine('.hbs', hbs({ | ||
25 | + extname: '.hbs', | ||
26 | + defaultLayout: 'layout', | ||
27 | + layoutsDir: doraemon, | ||
28 | + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
29 | + helpers: require(`${global.library}/helpers`) | ||
30 | +})); | ||
31 | + | ||
32 | + | ||
33 | +require('./auth'); | ||
34 | +app.use(passport.initialize()); | ||
35 | +app.use(passport.session()); | ||
36 | + | ||
37 | +// router | ||
38 | +app.use(require('./router')); | ||
39 | + | ||
40 | +module.exports = app; |
apps/passport/models/auth-helper.js
0 → 100644
1 | +'use strict'; | ||
2 | + | ||
3 | +const library = '../../../library'; | ||
4 | +const API = require(`${library}/api`).API; | ||
5 | +const sign = require(`${library}/sign`); | ||
6 | +const api = new API(); | ||
7 | + | ||
8 | +class Auth { | ||
9 | + | ||
10 | + static signinByOpenID(nickname, openId, sourceType, shoppingKey) { | ||
11 | + let param = { | ||
12 | + nickname: nickname, | ||
13 | + openId: openId, | ||
14 | + source_type: sourceType, // esline-disable-line | ||
15 | + method: 'app.passport.signinByOpenID', | ||
16 | + shoppingKey: shoppingKey | ||
17 | + }; | ||
18 | + | ||
19 | + if (shoppingKey) { | ||
20 | + param.shopping_key = shoppingKey; | ||
21 | + } | ||
22 | + | ||
23 | + return api.get('', sign.apiSign(param)); | ||
24 | + } | ||
25 | + | ||
26 | + static profile(uid) { | ||
27 | + let param = { | ||
28 | + uid: uid, | ||
29 | + method: 'app.passport.profile' | ||
30 | + }; | ||
31 | + | ||
32 | + return api.get('', sign.apiSign(param)); | ||
33 | + } | ||
34 | + | ||
35 | + static syncUserSession(uid, req, res) { | ||
36 | + return Auth.profile(uid).then((userInfo) => { | ||
37 | + let token = sign.makeToken(uid); | ||
38 | + let data = userInfo.data; | ||
39 | + | ||
40 | + if (data) { | ||
41 | + let uidCookie = `${data.profile_name}::${data.uid}::${data.vip_info.title}::${token}`; | ||
42 | + | ||
43 | + res.cookie('_UID', uidCookie, { | ||
44 | + domain: 'yohobuy.com' | ||
45 | + }); | ||
46 | + } | ||
47 | + req.session._TOKEN = token; // esline-disable-line | ||
48 | + req.session._LOGIN_UID = uid; // esline-disable-line | ||
49 | + res.cookie('token', token, { | ||
50 | + domain: 'yohobuy.com' | ||
51 | + }); // esline-disable-line | ||
52 | + }).catch(console.log); | ||
53 | + } | ||
54 | +} | ||
55 | + | ||
56 | +module.exports = Auth; |
apps/passport/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app channel | ||
3 | + * @author: Bi Kai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/09 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const express = require('express'); | ||
10 | +const cRoot = './controllers'; | ||
11 | +const login = require(cRoot + '/login'); | ||
12 | + | ||
13 | +const router = express.Router(); // eslint-disable-line | ||
14 | + | ||
15 | +router.get('/login/wechat', login.wechat.beforeLogin, login.wechat.login); // 登录 | ||
16 | +router.get('/login/wechat/callback', login.wechat.callback); | ||
17 | + | ||
18 | +module.exports = router; |
@@ -4,30 +4,30 @@ | @@ -4,30 +4,30 @@ | ||
4 | * @date: 2016/05/06 | 4 | * @date: 2016/05/06 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | - var express = require('express'), | ||
8 | - path = require('path'), | ||
9 | - hbs = require('express-handlebars'); | 7 | +var express = require('express'), |
8 | + path = require('path'), | ||
9 | + hbs = require('express-handlebars'); | ||
10 | 10 | ||
11 | - var app = express(); | 11 | +var app = express(); |
12 | 12 | ||
13 | - // set view engin | ||
14 | - var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | 13 | +// set view engin |
14 | +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | ||
15 | 15 | ||
16 | - app.on('mount', function(parent) { | ||
17 | - delete parent.locals.settings; // 不继承父 App 的设置 | ||
18 | - Object.assign(app.locals, parent.locals); | ||
19 | - }); | 16 | +app.on('mount', function(parent) { |
17 | + delete parent.locals.settings; // 不继承父 App 的设置 | ||
18 | + Object.assign(app.locals, parent.locals); | ||
19 | +}); | ||
20 | 20 | ||
21 | - app.set('views', path.join(__dirname, 'views/action')); | ||
22 | - app.engine('.hbs', hbs({ | ||
23 | - extname: '.hbs', | ||
24 | - defaultLayout: 'layout', | ||
25 | - layoutsDir: doraemon, | ||
26 | - partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
27 | - helpers: require(`${global.library}/helpers`) | ||
28 | - })); | 21 | +app.set('views', path.join(__dirname, 'views/action')); |
22 | +app.engine('.hbs', hbs({ | ||
23 | + extname: '.hbs', | ||
24 | + defaultLayout: 'layout', | ||
25 | + layoutsDir: doraemon, | ||
26 | + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
27 | + helpers: require(`${global.library}/helpers`) | ||
28 | +})); | ||
29 | 29 | ||
30 | - // router | ||
31 | - app.use(require('./router')); | 30 | +// router |
31 | +app.use(require('./router')); | ||
32 | 32 | ||
33 | - module.exports = app; | 33 | +module.exports = app; |
@@ -47,6 +47,12 @@ module.exports = { | @@ -47,6 +47,12 @@ module.exports = { | ||
47 | colorize: 'all', | 47 | colorize: 'all', |
48 | prettyPrint: true | 48 | prettyPrint: true |
49 | } | 49 | } |
50 | + }, | ||
51 | + thirdLogin: { | ||
52 | + wechat: { | ||
53 | + appID: 'wx75e5a7c0c88e45c2', | ||
54 | + appSecret: 'ce21ae4a3f93852279175a167e54509b' | ||
55 | + } | ||
50 | } | 56 | } |
51 | }; | 57 | }; |
52 | 58 |
@@ -3,6 +3,8 @@ | @@ -3,6 +3,8 @@ | ||
3 | * @param {[object]} req | 3 | * @param {[object]} req |
4 | * @return {[string]} | 4 | * @return {[string]} |
5 | */ | 5 | */ |
6 | +'use strict'; | ||
7 | + | ||
6 | exports.getUid = (req) => { | 8 | exports.getUid = (req) => { |
7 | const cookie = req.cookies._UID; | 9 | const cookie = req.cookies._UID; |
8 | let _uid = 0; | 10 | let _uid = 0; |
@@ -21,3 +23,7 @@ exports.getUid = (req) => { | @@ -21,3 +23,7 @@ exports.getUid = (req) => { | ||
21 | 23 | ||
22 | return _uid; | 24 | return _uid; |
23 | }; | 25 | }; |
26 | + | ||
27 | +exports.getShoppingKey = (req) => { | ||
28 | + return req.cookies['_SPK'] ? req.cookies['_SPK'] : ''; // eslint-disable-line | ||
29 | +}; |
@@ -11,12 +11,12 @@ const FileTransport = require('winston-daily-rotate-file'); | @@ -11,12 +11,12 @@ const FileTransport = require('winston-daily-rotate-file'); | ||
11 | 11 | ||
12 | require('influxdb-winston'); | 12 | require('influxdb-winston'); |
13 | 13 | ||
14 | -const logger = new (winston.Logger)({ | 14 | +const logger = new(winston.Logger)({ |
15 | transports: [ | 15 | transports: [ |
16 | - new (FileTransport)(config.loggers.infoFile), | ||
17 | - new (FileTransport)(config.loggers.errorFile), | ||
18 | - new (winston.transports.UdpTransport)(config.loggers.udp), | ||
19 | - new (winston.transports.Console)(config.loggers.console) | 16 | + new(FileTransport)(config.loggers.infoFile), |
17 | + new(FileTransport)(config.loggers.errorFile), | ||
18 | + new(winston.transports.UdpTransport)(config.loggers.udp), | ||
19 | + new(winston.transports.Console)(config.loggers.console) | ||
20 | ], | 20 | ], |
21 | exitOnError: false | 21 | exitOnError: false |
22 | }); | 22 | }); |
@@ -72,7 +72,7 @@ exports.apiSign = (params) => { | @@ -72,7 +72,7 @@ exports.apiSign = (params) => { | ||
72 | // 检查签名,APP 访问 H5 页面的时候需要检查 | 72 | // 检查签名,APP 访问 H5 页面的时候需要检查 |
73 | exports.checkSign = (params) => { | 73 | exports.checkSign = (params) => { |
74 | const // eslint-disable-line camelcase | 74 | const // eslint-disable-line camelcase |
75 | - clientSecret = params.client_secret; | 75 | + clientSecret = params.client_secret; |
76 | 76 | ||
77 | let sortedParams; | 77 | let sortedParams; |
78 | 78 | ||
@@ -94,3 +94,7 @@ exports.webSign = (params) => { | @@ -94,3 +94,7 @@ exports.webSign = (params) => { | ||
94 | 94 | ||
95 | return params.key === md5(md5(webPrivateKey) + params.uid); | 95 | return params.key === md5(md5(webPrivateKey) + params.uid); |
96 | }; | 96 | }; |
97 | + | ||
98 | +exports.makeToken = (string) => { | ||
99 | + return md5(md5(string + '#@!@#')); | ||
100 | +}; |
@@ -43,6 +43,8 @@ | @@ -43,6 +43,8 @@ | ||
43 | "moment": "^2.13.0", | 43 | "moment": "^2.13.0", |
44 | "morgan": "^1.7.0", | 44 | "morgan": "^1.7.0", |
45 | "oneapm": "^1.2.20", | 45 | "oneapm": "^1.2.20", |
46 | + "passport": "^0.3.2", | ||
47 | + "passport-weixin-plus": "0.0.4", | ||
46 | "request-promise": "^3.0.0", | 48 | "request-promise": "^3.0.0", |
47 | "serve-favicon": "^2.3.0", | 49 | "serve-favicon": "^2.3.0", |
48 | "uuid": "^2.0.2", | 50 | "uuid": "^2.0.2", |
-
Please register or login to post a comment