Authored by 毕凯

Merge branch 'hotfix/login' into 'master'

Hotfix/login



See merge request !454
@@ -31,4 +31,4 @@ exports.sidebar = function(req, res, next) { @@ -31,4 +31,4 @@ exports.sidebar = function(req, res, next) {
31 layout: false 31 layout: false
32 }); 32 });
33 }).catch(next); 33 }).catch(next);
34 -}  
  34 +};
@@ -81,7 +81,9 @@ const common = { @@ -81,7 +81,9 @@ const common = {
81 let passLogin = _.get(req, 'cookies._WX_PASS_LOGIN', false); 81 let passLogin = _.get(req, 'cookies._WX_PASS_LOGIN', false);
82 82
83 if (req.yoho.isWechat && !passLogin) { 83 if (req.yoho.isWechat && !passLogin) {
84 - return res.redirect('/passport/login/wechat'); 84 + return res.redirect(helpers.urlFormat('/passport/login/wechat', {
  85 + refer: req.query.refer || req.get('Referer') || '/'
  86 + }));
85 } 87 }
86 next(); 88 next();
87 }, 89 },
@@ -128,11 +130,13 @@ const local = { @@ -128,11 +130,13 @@ const local = {
128 // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie 130 // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
129 // res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800); 131 // res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
130 132
  133 + // 170406 账户密码方式登录可以选择是否开启验证码,默认开关是关闭状态,此时开启验证码,开关开启,无需验证
  134 + let captchaShow = _.get(req.app.locals.wap, 'close.loginValidation', false);
131 135
132 res.render('login', { 136 res.render('login', {
133 width750: true, 137 width750: true,
134 loginIndex: true, // 模板中使用JS的标识 138 loginIndex: true, // 模板中使用JS的标识
135 - captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码 139 + captchaShow: !captchaShow, // 170306 因为暴力破解密码问题,要求每次都展示验证码
136 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 140 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
137 showHeaderImg: true, // 控制显示头部图片 141 showHeaderImg: true, // 控制显示头部图片
138 isPassportPage: true, // 模板中模块标识 142 isPassportPage: true, // 模板中模块标识
@@ -170,13 +174,14 @@ const local = { @@ -170,13 +174,14 @@ const local = {
170 // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie 174 // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
171 // res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800); 175 // res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
172 176
173 - 177 + // 170406 账户密码方式登录可以选择是否开启验证码,默认开关是关闭状态,此时开启验证码,开关开启,无需验证
  178 + let captchaShow = _.get(req.app.locals.wap, 'close.loginValidation', false);
174 179
175 res.render('international', { 180 res.render('international', {
176 width750: true, 181 width750: true,
177 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 182 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
178 loginInternational: true, // 模板中使用JS的标识 183 loginInternational: true, // 模板中使用JS的标识
179 - captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码 184 + captchaShow: !captchaShow, // 170306 因为暴力破解密码问题,要求每次都展示验证码
180 isPassportPage: true, // 模板中模块标识 185 isPassportPage: true, // 模板中模块标识
181 headerText: '登录', 186 headerText: '登录',
182 areaCode: '+86', // 默认区号 187 areaCode: '+86', // 默认区号
@@ -250,6 +255,18 @@ const local = { @@ -250,6 +255,18 @@ const local = {
250 255
251 const wechat = { 256 const wechat = {
252 login: (req, res, next) => { 257 login: (req, res, next) => {
  258 + // 微信里边已经登录的时候,不再跳转登录
  259 + if (req.user.uid) {
  260 + let refer = req.query.refer || decodeURI(req.cookies.refer) || config.siteUrl;
  261 +
  262 + if (/sign|login/.test(refer)) {
  263 + refer = `${config.siteUrl}/home`;
  264 + }
  265 +
  266 + refer = utils.refererLimit(refer);
  267 + return res.redirect(refer);
  268 + }
  269 +
253 // 设置为原链接标识originalUrl 270 // 设置为原链接标识originalUrl
254 req.session.originalUrl = 'true'; 271 req.session.originalUrl = 'true';
255 req.session.authState = uuid.v4(); 272 req.session.authState = uuid.v4();
@@ -20,6 +20,11 @@ const check = (req, res, next) => { @@ -20,6 +20,11 @@ const check = (req, res, next) => {
20 return next(); 20 return next();
21 } 21 }
22 22
  23 + // 170406 采用账号密码方式登录验证码可以配置关闭,默认开关是关闭状态,这时需要验证,开关开启,无需验证
  24 + if (_.get(req.app.locals.wap, 'close.loginValidation', false) && req.path === '/passport/login/auth') {
  25 + return next();
  26 + }
  27 +
23 // 使用极验证 28 // 使用极验证
24 let useGeetest = !_.get(req.app.locals.wap, 'geetest.validation', false); 29 let useGeetest = !_.get(req.app.locals.wap, 'geetest.validation', false);
25 30
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 const _ = require('lodash'); 2 const _ = require('lodash');
3 const aes = require('./aes-pwd'); 3 const aes = require('./aes-pwd');
4 const authcode = require('../../../utils/authcode'); 4 const authcode = require('../../../utils/authcode');
  5 +const logger = global.yoho.logger;
5 const sign = global.yoho.sign; 6 const sign = global.yoho.sign;
6 const api = global.yoho.API; 7 const api = global.yoho.API;
7 const uuid = require('uuid'); 8 const uuid = require('uuid');
@@ -35,10 +36,13 @@ class Auth { @@ -35,10 +36,13 @@ class Auth {
35 param.shopping_key = shoppingKey; 36 param.shopping_key = shoppingKey;
36 } 37 }
37 38
  39 + logger.info(`${profile}, login from ${ip}`);
  40 +
38 return api.post('', param, { 41 return api.post('', param, {
39 headers: { 42 headers: {
40 'user-agent': 'yoho/nodejs', 43 'user-agent': 'yoho/nodejs',
41 - 'X-YOHO-IP': ip 44 + 'X-YOHO-IP': ip,
  45 + 'X-Forwarded-For': ip
42 } 46 }
43 }); 47 });
44 } 48 }
@@ -27,7 +27,7 @@ const router = express.Router(); // eslint-disable-line @@ -27,7 +27,7 @@ const router = express.Router(); // eslint-disable-line
27 router.get('/passport/geetest/register', geetest.register); 27 router.get('/passport/geetest/register', geetest.register);
28 28
29 // 兼容老的路由 29 // 兼容老的路由
30 -router.get('/signin.html', validateCode.load, login.common.weixinCheck, 30 +router.get('/signin.html', login.common.weixinCheck, validateCode.load,
31 login.common.beforeLogin, login.common.clearCookie, smsLogin.loginPage); 31 login.common.beforeLogin, login.common.clearCookie, smsLogin.loginPage);
32 router.get('/reg.html', validateCode.load, disableBFCahce, reg.index); 32 router.get('/reg.html', validateCode.load, disableBFCahce, reg.index);
33 router.get('/login.html', validateCode.load, 33 router.get('/login.html', validateCode.load,
@@ -78,10 +78,6 @@ router.get('/passport/login/qq/callback', login.qq.callback); @@ -78,10 +78,6 @@ router.get('/passport/login/qq/callback', login.qq.callback);
78 router.get('/passport/login/alipay', login.common.beforeLogin, login.alipay.login); 78 router.get('/passport/login/alipay', login.common.beforeLogin, login.alipay.login);
79 router.get('/passport/login/alipay/callback', login.alipay.callback); 79 router.get('/passport/login/alipay/callback', login.alipay.callback);
80 80
81 -// alipay登录  
82 -router.get('/login/alipay', login.common.beforeLogin, login.alipay.login);  
83 -router.get('/login/alipay/callback', login.alipay.callback);  
84 -  
85 // 登录绑定 81 // 登录绑定
86 router.get('/passport/bind/index', validateCode.load, bind.indexPage); 82 router.get('/passport/bind/index', validateCode.load, bind.indexPage);
87 router.post('/passport/bind/bindCheck', validateCode.check, bind.bindCheck); 83 router.post('/passport/bind/bindCheck', validateCode.check, bind.bindCheck);
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 <input id="pwd" class="pwd input" type="password" placeholder="密码"> 10 <input id="pwd" class="pwd input" type="password" placeholder="密码">
11 </div> 11 </div>
12 {{!--图片验证--}} 12 {{!--图片验证--}}
13 - <div data-geetest="{{useGeetest}}" id="js-img-check"></div> 13 + <div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check"></div>
14 14
15 <span id="btn-login" class="btn btn-login disble row">登录</span> 15 <span id="btn-login" class="btn btn-login disble row">登录</span>
16 </div> 16 </div>
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 <input id="pwd" class="pwd input" type="password" placeholder="密码"> 9 <input id="pwd" class="pwd input" type="password" placeholder="密码">
10 </div> 10 </div>
11 {{!--图片验证--}} 11 {{!--图片验证--}}
12 - <div data-geetest="{{useGeetest}}" id="js-img-check"></div> 12 + <div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check"></div>
13 <span id="btn-login" class="btn btn-login disable">登录</span> 13 <span id="btn-login" class="btn btn-login disable">登录</span>
14 <p class="op-container"> 14 <p class="op-container">
15 <a class="op-item internat" href={{internationalUrl}}>海外手机</a> 15 <a class="op-item internat" href={{internationalUrl}}>海外手机</a>
@@ -22,7 +22,7 @@ module.exports = (req, res, next) => { @@ -22,7 +22,7 @@ module.exports = (req, res, next) => {
22 return next(); 22 return next();
23 } 23 }
24 24
25 - if (res.statusCode == 403) { 25 + if (_.toNumber(res.statusCode) === 403) {
26 return res.end(); 26 return res.end();
27 } 27 }
28 28
@@ -21,7 +21,11 @@ const _getClientIp = req => { @@ -21,7 +21,11 @@ const _getClientIp = req => {
21 remoteIp = _.trim(arr[arr.length - 1]); 21 remoteIp = _.trim(arr[arr.length - 1]);
22 } 22 }
23 23
24 - return remoteIp; 24 + if (_.startsWith(remoteIp, '10.66.')) {
  25 + remoteIp = req.get('X-Real-IP');
  26 + }
  27 +
  28 + return _.trim(remoteIp);
25 }; 29 };
26 30
27 module.exports = () => { 31 module.exports = () => {
1 { 1 {
2 "name": "m-yohobuy-node", 2 "name": "m-yohobuy-node",
3 - "version": "5.5.11", 3 + "version": "5.5.12",
4 "private": true, 4 "private": true,
5 "description": "A New Yohobuy Project With Express", 5 "description": "A New Yohobuy Project With Express",
6 "repository": { 6 "repository": {
@@ -13,6 +13,7 @@ let $phoneNum = $('#phone-num'), @@ -13,6 +13,7 @@ let $phoneNum = $('#phone-num'),
13 $loginBtn = $('#btn-login'), 13 $loginBtn = $('#btn-login'),
14 14
15 $captcha = $('#js-img-check'), 15 $captcha = $('#js-img-check'),
  16 + useVerify = $captcha.data('userverify'), // 170406 是否使用验证
16 17
17 pnPass = false, 18 pnPass = false,
18 pwdPass = false; 19 pwdPass = false;
@@ -23,15 +24,18 @@ let tip = require('plugin/tip'); @@ -23,15 +24,18 @@ let tip = require('plugin/tip');
23 let trim = $.trim; 24 let trim = $.trim;
24 let showErrTip = tip.show; 25 let showErrTip = tip.show;
25 26
26 -let validate = new Validate($captcha, { 27 +let validate = {};
  28 +
  29 +if (useVerify) {
  30 + validate = new Validate($captcha, {
27 useREM: { 31 useREM: {
28 rootFontSize: 40, 32 rootFontSize: 40,
29 picWidth: 150 33 picWidth: 150
30 } 34 }
31 -});  
32 -  
33 -validate.init(); 35 + });
34 36
  37 + validate.init();
  38 +}
35 39
36 // 登录按钮状态切换 40 // 登录按钮状态切换
37 function switchLoginBtnStatus() { 41 function switchLoginBtnStatus() {
@@ -45,6 +49,47 @@ function resetForm() { @@ -45,6 +49,47 @@ function resetForm() {
45 $loginBtn.text('登录').addClass('disable'); 49 $loginBtn.text('登录').addClass('disable');
46 } 50 }
47 51
  52 +/**
  53 + * 登录校验
  54 + */
  55 +function loginAuth(params) {
  56 + $.ajax({
  57 + type: 'POST',
  58 + url: '/passport/login/auth',
  59 + data: params,
  60 + success: function(data) {
  61 + let res;
  62 +
  63 + validate && validate.type === 2 && validate.refresh();
  64 + if (data.code === 200) {
  65 + res = data.data;
  66 + showErrTip('登录成功');
  67 +
  68 + // 3秒后强制跳转
  69 + setTimeout(() => {
  70 + location.href = res.href;
  71 + }, 1500);
  72 +
  73 + $loginBtn.text('登录成功');
  74 + showErrTip('登录成功');
  75 + } else {
  76 + if (useVerify && data.captchaShow) {
  77 + ((data.changeCaptcha && validate.type !== 2) && validate.refresh());
  78 + }
  79 +
  80 + showErrTip(data.message);
  81 + resetForm();
  82 + }
  83 + },
  84 + error: function() {
  85 + showErrTip('网络断开连接啦~');
  86 + $loginBtn.text('登录');
  87 +
  88 + validate && validate.refresh();
  89 + }
  90 + });
  91 +}
  92 +
48 // Android-UC下显示select的direction:rtl无效的临时解决办法 93 // Android-UC下显示select的direction:rtl无效的临时解决办法
49 api.selectCssHack($countrySelect); 94 api.selectCssHack($countrySelect);
50 95
@@ -90,52 +135,21 @@ $loginBtn.on('touchstart', function() { @@ -90,52 +135,21 @@ $loginBtn.on('touchstart', function() {
90 } 135 }
91 136
92 if ((api.phoneRegx[areaCode].test(pn) || areaCode !== '+86') && api.pwdValidate(pwd)) { 137 if ((api.phoneRegx[areaCode].test(pn) || areaCode !== '+86') && api.pwdValidate(pwd)) {
93 - validate.getResults().then((result) => {  
94 - $loginBtn.text('正在登录...').addClass('disable');  
95 let params = { 138 let params = {
96 areaCode: areaCode.replace('+', ''), 139 areaCode: areaCode.replace('+', ''),
97 account: pn, 140 account: pn,
98 password: pwd 141 password: pwd
99 }; 142 };
100 143
  144 + if (useVerify) {
  145 + validate.getResults().then((result) => {
  146 + $loginBtn.text('正在登录...').addClass('disable');
101 $.extend(params, result); 147 $.extend(params, result);
102 -  
103 - $.ajax({  
104 - type: 'POST',  
105 - url: '/passport/login/auth',  
106 - data: params,  
107 - success: function(data) {  
108 - let res;  
109 -  
110 - validate.type === 2 && validate.refresh();  
111 - if (data.code === 200) {  
112 - res = data.data;  
113 - showErrTip('登录成功');  
114 -  
115 - // 3秒后强制跳转  
116 - setTimeout(() => {  
117 - location.href = res.href;  
118 - }, 1500);  
119 -  
120 - $loginBtn.text('登录成功');  
121 - showErrTip('登录成功'); 148 + loginAuth(params);
  149 + });
122 } else { 150 } else {
123 - if (data.captchaShow) {  
124 - ((data.changeCaptcha && validate.type !== 2) && validate.refresh()); 151 + loginAuth(params);
125 } 152 }
126 -  
127 - showErrTip(data.message);  
128 - resetForm();  
129 - }  
130 - },  
131 - error: function() {  
132 - showErrTip('网络断开连接啦~');  
133 - $loginBtn.text('登录');  
134 -  
135 - validate.refresh();  
136 - }  
137 - });  
138 - });  
139 } else { 153 } else {
140 showErrTip('账号或密码有错误,请重新输入'); 154 showErrTip('账号或密码有错误,请重新输入');
141 $loginBtn.text('登录').addClass('disable'); 155 $loginBtn.text('登录').addClass('disable');
@@ -14,6 +14,7 @@ let $account = $('#account'), @@ -14,6 +14,7 @@ let $account = $('#account'),
14 $ways = $('#retrive-pwd-ways'), 14 $ways = $('#retrive-pwd-ways'),
15 15
16 $captcha = $('#js-img-check'), 16 $captcha = $('#js-img-check'),
  17 + useVerify = $captcha.data('userverify'), // 170406 是否使用验证
17 18
18 accPass = false, 19 accPass = false,
19 pwdPass = false; 20 pwdPass = false;
@@ -25,14 +26,18 @@ let trim = $.trim; @@ -25,14 +26,18 @@ let trim = $.trim;
25 let showErrTip = tip.show; 26 let showErrTip = tip.show;
26 27
27 28
28 -let validate = new Validate($captcha, { 29 +let validate = {};
  30 +
  31 +if (useVerify) {
  32 + validate = new Validate($captcha, {
29 useREM: { 33 useREM: {
30 rootFontSize: 40, 34 rootFontSize: 40,
31 picWidth: 150 35 picWidth: 150
32 } 36 }
33 -}); 37 + });
34 38
35 -validate.init(); 39 + validate.init();
  40 +}
36 41
37 // 登录按钮状态切换 42 // 登录按钮状态切换
38 function switchLoginBtnStatus() { 43 function switchLoginBtnStatus() {
@@ -60,51 +65,10 @@ function hideRetrivePanel() { @@ -60,51 +65,10 @@ function hideRetrivePanel() {
60 $ways.hide(); 65 $ways.hide();
61 } 66 }
62 67
63 -// 密码显示与隐藏  
64 -api.bindEyesEvt();  
65 -  
66 -// 清空账号输入框  
67 -api.bindClearEvt();  
68 -  
69 -$account.bind('input', function() {  
70 - if (trim($account.val()) !== '') {  
71 - accPass = true;  
72 - } else {  
73 - accPass = false;  
74 - }  
75 - switchLoginBtnStatus();  
76 -});  
77 -  
78 -$pwd.bind('input', function() {  
79 - if (trim($pwd.val()) === '') {  
80 - pwdPass = false;  
81 - } else {  
82 - pwdPass = true;  
83 - }  
84 - switchLoginBtnStatus();  
85 -});  
86 -  
87 -  
88 -// Login  
89 -$loginBtn.on('touchstart', function() {  
90 - if ($loginBtn.hasClass('disable')) {  
91 - return;  
92 - }  
93 - let acc = trim($account.val()),  
94 - pwd = trim($pwd.val());  
95 -  
96 - // 验证账号(数字或者邮箱)和密码合理性  
97 - if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) {  
98 - validate.getResults().then((result) => {  
99 - $loginBtn.text('正在登录...').addClass('disable');  
100 -  
101 - let params = {  
102 - account: acc,  
103 - password: pwd  
104 - };  
105 -  
106 - $.extend(params, result);  
107 - 68 +/**
  69 + * 登录校验
  70 + */
  71 +function loginAuth(params, acc) {
108 $.ajax({ 72 $.ajax({
109 type: 'POST', 73 type: 'POST',
110 url: '/passport/login/auth', 74 url: '/passport/login/auth',
@@ -128,7 +92,7 @@ $loginBtn.on('touchstart', function() { @@ -128,7 +92,7 @@ $loginBtn.on('touchstart', function() {
128 }) 92 })
129 }, true); 93 }, true);
130 } 94 }
131 - validate.type === 2 && validate.refresh(); 95 + validate && validate.type === 2 && validate.refresh();
132 if (data.code === 200) { 96 if (data.code === 200) {
133 res = data.data; 97 res = data.data;
134 98
@@ -136,7 +100,7 @@ $loginBtn.on('touchstart', function() { @@ -136,7 +100,7 @@ $loginBtn.on('touchstart', function() {
136 location.href = res.href; 100 location.href = res.href;
137 $loginBtn.text('登录成功'); 101 $loginBtn.text('登录成功');
138 } else { 102 } else {
139 - if (data.captchaShow) { 103 + if (useVerify && data.captchaShow) {
140 ((data.changeCaptcha && validate.type !== 2) && validate.refresh()); 104 ((data.changeCaptcha && validate.type !== 2) && validate.refresh());
141 } 105 }
142 106
@@ -149,14 +113,67 @@ $loginBtn.on('touchstart', function() { @@ -149,14 +113,67 @@ $loginBtn.on('touchstart', function() {
149 error: function() { 113 error: function() {
150 showErrTip('网络断开连接啦~'); 114 showErrTip('网络断开连接啦~');
151 115
152 - validate.refresh(); 116 + validate && validate.refresh();
153 }, 117 },
154 complete: function() { 118 complete: function() {
155 $loginBtn.text('登录').removeClass('disable'); 119 $loginBtn.text('登录').removeClass('disable');
156 } 120 }
157 }); 121 });
  122 +}
  123 +
  124 +// 密码显示与隐藏
  125 +api.bindEyesEvt();
  126 +
  127 +// 清空账号输入框
  128 +api.bindClearEvt();
  129 +
  130 +$account.bind('input', function() {
  131 + if (trim($account.val()) !== '') {
  132 + accPass = true;
  133 + } else {
  134 + accPass = false;
  135 + }
  136 + switchLoginBtnStatus();
  137 +});
  138 +
  139 +$pwd.bind('input', function() {
  140 + if (trim($pwd.val()) === '') {
  141 + pwdPass = false;
  142 + } else {
  143 + pwdPass = true;
  144 + }
  145 + switchLoginBtnStatus();
  146 +});
  147 +
  148 +
  149 +// Login
  150 +$loginBtn.on('touchstart', function() {
  151 + if ($loginBtn.hasClass('disable')) {
  152 + return;
  153 + }
  154 + let acc = trim($account.val()),
  155 + pwd = trim($pwd.val());
  156 +
  157 + // 验证账号(数字或者邮箱)和密码合理性
  158 + if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) {
  159 + let params = {
  160 + account: acc,
  161 + password: pwd
  162 + };
  163 +
  164 + if (useVerify) {
  165 + validate.getResults().then((result) => {
  166 + $loginBtn.text('正在登录...').addClass('disable');
  167 +
  168 + $.extend(params, result);
  169 +
  170 + // auth
  171 + loginAuth(params, acc);
158 }, () => {}); 172 }, () => {});
159 } else { 173 } else {
  174 + loginAuth(params, acc);
  175 + }
  176 + } else {
160 showErrTip('账号或密码有错误,请重新输入'); 177 showErrTip('账号或密码有错误,请重新输入');
161 $loginBtn.text('登录').removeClass('disable'); 178 $loginBtn.text('登录').removeClass('disable');
162 } 179 }