Authored by htoooth

addjs

... ... @@ -37,21 +37,11 @@ passport.use('local', new LocalStrategy({
let area = req.body.areaCode || '86';
if (isNaN(_.parseInt(area)) || _.isEmpty(username) || _.isEmpty(password)) {
if (_.isEmpty(password)) {
logger.info(`【Passport Loginbad params, area:${area} account:${username} password:${password}`);
return done({message: '登录参数错误'}, null);
}
let verifyEmail = helpers.verifyEmail(username);
// 国际号码验证取消
let verifyMobile = area === '86' ? helpers.verifyAreaMobile(area + '-' + username) : true;
if (!verifyEmail && !verifyMobile) {
logger.info(`【Passport Loginbad account, email:${verifyEmail} mobile:${verifyMobile}`);
return done({message: '登录账号格式错误'}, null);
}
let expire = req.cookies['LE' + md5('_LOGIN_EXPIRE')];
if (_.isEmpty(expire) || expire < (new Date()).getTime() / 1000) {
... ...
... ... @@ -289,6 +289,87 @@ const local = {
}
}).catch(next);
}
},
qrcode: {
refresh: (req, res, next) => {
AuthHelper.fetchByQrCode().then((result) => {
if (result.code === 200) {
return res.json({
code: 200,
data: {
qrcode: `http://m.yohobuy.com/signin.html?qr=${result.data.code}`
}
});
} else {
return res.json({
code: 400,
message: '生成二维码错误'
});
}
}).catch(next);
},
check: (req, res, next) => {
let qrcode = req.body.qrcode || '';
if (!qrcode) {
return res.json({
code: 400,
message: '输入错误,请重新刷新二维码'
});
}
if (!_.includes(qrcode, '=')) {
return res.json({
code: 400,
message: '输入错误,请重新刷新二维码'
});
}
let token = qrcode.substring(qrcode.indexOf('=') + 1);
AuthHelper.checkByQrCode(token).then((result) => {
console.log(result);
if (_.isEmpty(result)) {
return res.json({
code: 400,
message: '输入错误,请重新刷新二维码'
});
}
if (result.code === 402) {
return res.json({
code: 402,
message: '二维码为空'
});
}
if (result.code === 403) {
return res.json({
code: 403,
message: '二维码未失效,不可登录'
});
}
if (result.code === 404) {
return res.json({
code: 404,
message: '二维码失效,需要重新刷新'
});
}
if (result.code === 200) {
return res.json({
code: 200,
message: '可以登录'
});
}
return res.json({
code: 400,
message: '服务器问题'
});
}).catch(next);
}
}
};
... ...
'use strict';
const md5 = require('md5');
const _ = require('lodash');
const aes = require('./aes-pwd');
const cache = global.yoho.cache;
const sign = global.yoho.sign;
... ... @@ -11,7 +13,8 @@ const Auth = {
let _that = this;
let loginBy = {
password: _that.signinByPasswordWithAes,
sms: _that.signinBySMS
sms: _that.signinBySMS,
qrocde: _that.signinByQrCode
};
return loginBy[type](area, profile, password, shoppingKey);
... ... @@ -44,6 +47,50 @@ const Auth = {
return api.post('', param);
},
// 这里的参数 __1 __2 占位参数
signinByQrCode(__1, __2, code, shoppingKey) { // eslint-disable-line
let param = {
method: 'app.twoDimen.qrCodeLogin',
code: code
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
return api.post('', param).then((result) => {
if (_.isEmpty(result)) {
return {
code: 400,
message: '出错了'
};
}
if (result.code !== 200) {
return {
code: 400,
message: '登录失败'
};
}
return result.data;
});
},
fetchByQrCode() {
let param = {
method: 'app.twoDimen.getCode'
};
return api.post('', param);
},
checkByQrCode(code) {
let param = {
method: 'app.twoDimen.loginCheck',
code: code
};
return api.post('', param);
},
sendPasswordBySMS(area, mobile) {
let param = {
method: 'app.message.sendSms',
... ...
... ... @@ -29,6 +29,10 @@ router.post('/passport/login/sms/auth', login.local.sms.auth); // 验证短信
router.post('/passport/login/sms/checkuser', login.local.sms.checkUser); // 短信检查用户是否注册
router.post('/passport/login/password/checkuser', back.validateInputAPI, back.getUserInfoAPI);// 密码登录检查用户是否注册
// 二维码登录
router.post('/passport/login/qrcode/refresh', login.local.qrcode.refresh); // 刷新二维码
router.post('/passport/login/qrcode/check', login.local.qrcode.check); // 验证二维码的状态
router.get('/passport/login', login.common.beforeLogin, login.local.loginPage);
router.post('/passport/login/auth', login.local.login);
router.get('/passport/logout', login.local.logout);
... ...
... ... @@ -35,18 +35,20 @@
</div>
</li>
<li class="relative password-login">
<input id="account1" class="account input va" name="account" value="{{bindMobile}}" type="text"
placeholder="邮箱/手机号码" autocomplete="off">
<li class="relative password-login">
<input id="account1" class="account input va" name="account" value="{{bindMobile}}"
type="text"
placeholder="邮箱/手机号码" autocomplete="off">
<span class="err-tip hide">
<i></i>
<em></em>
</span>
</li>
<li class="relative password-login">
<input id="password" class="password input va" name="password" type="password" placeholder="密码"
autocomplete="off" maxlength="20">
<span id="caps-lock" class="caps-lock hide">大写状态开启</span>
</li>
<li class="relative password-login">
<input id="password" class="password input va" name="password" type="password"
placeholder="密码"
autocomplete="off" maxlength="20">
<span id="caps-lock" class="caps-lock hide">大写状态开启</span>
<span class="err-tip hide">
<i></i>
<em>请输入密码</em>
... ... @@ -54,20 +56,21 @@
</li>
<li class="relative clearfix sms-login hide">
<input id="account2" class="account input va" name="account2" value="{{bindMobile}}" type="text"
placeholder="手机号码" autocomplete="off">
<li class="relative clearfix sms-login hide">
<input id="account2" class="account input va" name="account2" value="{{bindMobile}}"
type="text"
placeholder="手机号码" autocomplete="off">
<span class="err-tip hide">
<i></i>
<em></em>
</span>
</li>
</li>
<li class="relative clearfix sms-login hide">
<input id="captcha-sms" class="input va captcha-sms-input" type="text" name="captcha"
placeholder="短信验证码"
autocomplete="off" maxlength="4">
<div class="change-captcha-sms btn">获取短信验证码</div>
<li class="relative clearfix sms-login hide">
<input id="captcha-sms" class="input va captcha-sms-input" type="text" name="captcha"
placeholder="短信验证码"
autocomplete="off" maxlength="4">
<div class="change-captcha-sms btn">获取短信验证码</div>
<span class="err-tip hide">
<i></i>
<em></em>
... ... @@ -132,29 +135,30 @@
<li class="relative clearfix center">
<div class="qrcode"></div>
<div id="overlay" class="qrcode-overlay"></div>
<div id="qrcode-container" class="qrcode"></div>
<div id="qrcode-overlay"></div>
</li>
<li class="relative clearfix">
<div>
<i class="scan"></i>
<p class="scan-font">打开手机Yoho!Buy有货</p>
<p class="scan-font">扫一扫登录</p>
</div>
</li>
<li class="relative clearfix center">
<div>
<a class="download-link" href="http://www.yohobuy.com/download/app">下载Yoho!Buy有货手机APP</a>
<a class="download-link"
href="http://www.yohobuy.com/download/app">下载Yoho!Buy有货手机APP</a>
</div>
</li>
</div>
</ul>
<input id="country-code-hide" name="countryCode" type="hidden" value="{{countryCode}}">
<input id="captcha-sms-token-hide" name="token" type="hidden">
<input id="qrcode" name="qrcode" type="hidden" value="//m.yohobuy.com/qrcode=1214124125">
<input id="qrcode" name="qrcode" type="hidden" value="//m.yohobuy.com/signin.html">
<input id="uid" type="hidden">
</div>
</form>
{{/ passport}}
... ...
... ... @@ -16,7 +16,7 @@ module.exports = {
siteUrl: 'http://www.yohobuy.com',
domains: {
favApi: 'http://192.168.102.31:8092/brower',
api: 'http://api.yoho.yohoops.org/',
api: 'http://dev-api.yohops.com:9999/',
service: 'http://service.yoho.yohoops.org/',
search: 'http://search.yohoops.org/yohosearch/'
},
... ...

6.45 MB | W: | H:

6.45 MB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -8,7 +8,10 @@
/* 流程 */
/** ************************************************************************/
/**
* 登录分为:普通登录(使用帐户和密码登录)和手机验证码登录(使用手机号和验证短信登录)
* 登录分为:
* 1.普通登录(使用帐户和密码登录)
* 2.短信验证码登录(使用手机号和验证短信登录)
* 3.二维码登录
*
* 每种登录的流程都是一致的,具体如下:
* 1. 各个输入框失去焦点验证(包括本地和网络)。
... ... @@ -21,6 +24,9 @@
* 手机验证码登录
* 帐号验证 => 手机短信验证 => 图形验证码验证 => 登录之前验证 => 登录
* 注意: **短信验证使用的是验证短信成功后的code进行登录**
*
* 二维码登录
* 生成二维码 => 轮询二维码 => 成功后 => 用二维码登录 => 登录
*/
/** ************************************************************************/
... ... @@ -89,7 +95,9 @@ var $accountInput1 = $('#account1'),
getQrCodeVal = function() {
return $qrcodeInput.val();
},
$qrCodeContainer = $('.qrcode');
$qrCodeContainer = $('#qrcode-container'),
$qrCodeOverlay = $('#qrcode-overlay'),
timerCheckQrCode;
// 提示
var $accountTip1 = $accountInput1.siblings('.err-tip'),
... ... @@ -114,6 +122,9 @@ var checkboxSymbol = {
// 短信验证码的时间间隔,60s
var second = 60;
// 检查二维码的时间 3s
var CHECK_INTERVAL = 3000;
// 只能验证一次
var isSmsCheckedSuccess = false;
... ... @@ -122,7 +133,7 @@ var isSmsCheckedSuccess = false;
/** ************************************************************************/
var accountChangeLoginTypeEvent = $.Callbacks(); //eslint-disable-line
var currentLogin = null;
var $switchLoginType = $('.switch');
var $switchPhoneLoginType = $('.switch');
var AccountLoginType = {
PasswordLogin: {
ele: '.password-login',
... ... @@ -195,13 +206,24 @@ var AccountLoginType = {
getAccountVal: getAccountVal2, // eslint-disable-line
showAccountTip: showAccountTip2, // eslint-disable-line
hideAccountTip: hideAccountTip2 // eslint-disable-line
},
QRCodeLogin: {
type: function() {
return 'qrcode';
},
getAccountVal: function() {
return $.trim($('#uid').val());
},
creditableToken: getQrCodeVal,
validate: function() {
return $.Deferred().resolve().promise(); // eslint-disable-line
}
}
};
/** ************************************************************************/
/* 设备登录类型 */
/** ************************************************************************/
var deviceChangeLoginTypeEvent = $.Callbacks(); //eslint-disable-line
var $switchDeviceType = $('#device-bg');
var DeviceLoginType = {
DesktopLogin: {
... ... @@ -223,9 +245,21 @@ var DeviceLoginType = {
};
var $deviceTips = $('.type-tip');
var desktopTipShowOnce = $.Callbacks('once'); //eslint-disable-line
var mobileTipShowOnce = $.Callbacks('once'); //eslint-disable-line
var desktopShowOnce = $.Callbacks('once'); //eslint-disable-line
var mobileShowOnce = $.Callbacks('once'); //eslint-disable-line
var QR_CODE_ERR = {
fail: '扫描失败',
error: '二维码已失效'
};
var tpl = function(text) {
return [
'<div class="qrcode-err-tip">',
text,
'</div><a id="qrcode-refresh-btn" class="qrcode-refresh-btn">请点击刷新</a>'
].join('');
};
// 切换登录方式
accountChangeLoginTypeEvent.add(function(type) {
... ... @@ -244,6 +278,8 @@ accountChangeLoginTypeEvent.add(function() {
$captchaImgInput.val('');
$captchaSmsInput.val('');
$captchaSmsTokenHideInput.val('');
qrcodeDefaultValue(); // eslint-disable-line
$qrCodeOverlay.empty();
});
// placeholder 变化
... ... @@ -255,11 +291,11 @@ accountChangeLoginTypeEvent.add(function(type) {
}
});
desktopShowOnce.add(function() {
desktopTipShowOnce.add(function() {
$deviceTips.removeClass('hide');
});
mobileShowOnce.add(function() {
mobileTipShowOnce.add(function() {
$deviceTips.removeClass('hide');
});
... ... @@ -334,6 +370,25 @@ function hideCaptchaSmsTip() {
return errTipHide($captchaSmsTip, $captchaSmsInput);
}
/**************************************************************************/
// qrcode
function showQrCodeTip(msg) {
$qrCodeOverlay.addClass('qrcode-overlay-fail');
$qrCodeOverlay.append(tpl(msg));
}
function hideQrCodeTip() {
$qrCodeOverlay.empty();
$qrCodeOverlay.removeClass('qrcode-overlay-fail');
}
function showQrCodeSuccess() {
$qrCodeOverlay.addClass('qrcode-overlay-success');
$qrCodeOverlay.css({
left: '65px'
});
}
/** ************************************************************************/
/* 用户帐号验证 */
/** ************************************************************************/
... ... @@ -662,6 +717,72 @@ function preSmsLoginWithValidate() {
}()).then(validateWithSmsMode);
}
/**************************************************************************/
/* 二维码 */
/**************************************************************************/
function refreshQrCode() {
return $.ajax({
url: '/passport/login/qrcode/refresh',
type: 'POST',
data: {}
}).then(function(result) {
hideQrCodeTip();
$qrCodeContainer.empty();
$qrCodeContainer.qrcode({
render: 'table',
size: 140,
text: result.data.qrcode
});
$qrcodeInput.val(result.data.qrcode);
timerCheckQrCodeAsync(); // eslint-disable-line
});
}
function validateQrCodeAsync(code) {
return $.ajax({
url: '/passport/login/qrcode/check',
type: 'POST',
data: {
qrcode: code
}
});
}
function timerCheckQrCodeAsync() {
timerCheckQrCode = window.setTimeout(function() {
validateQrCodeAsync(getQrCodeVal).then(function(result) {
clearTimerQrCode(); // eslint-disable-line
if (result.code === 200) {
showQrCodeSuccess();
login(); // eslint-disable-line
} else if (result.code === 403) {
setImmediate(function() {
timerCheckQrCodeAsync();
});
} else {
showQrCodeTip(QR_CODE_ERR.fail);
}
});
}, CHECK_INTERVAL);
}
function clearTimerQrCode() {
clearTimeout(timerCheckQrCode);
timerCheckQrCode = null;
}
function qrcodeDefaultValue() {
$('.qrcode').empty().qrcode({
render: 'table',
size: 150,
text: '//m.yohobuy.com/signin.html'
});
}
/** ************************************************************************/
/* 帮助函数 */
/** ************************************************************************/
... ... @@ -745,9 +866,12 @@ function login() {
if (currentLogin.type() === 'password') {
showPasswordTip(res.message);
$passwordInput.addClass('error').val('');
} else {
} else if (currentLogin.type() === 'sms') {
showCaptchaSmsTip('短信验证码错误');
$captchaSmsInput.addClass('error').val('');
} else if (currentLogin.type() === 'qrcode') {
// noting to do
showQrCodeTip(QR_CODE_ERR.fail);
}
}
... ... @@ -795,7 +919,7 @@ $(document).on('click', function(e) {
/** ************************************************************************/
// 邮箱自动完成后失去焦点:1. 本地验证格式;2.服务器检查用户是否注册;3.检查验证用户次数
// 邮箱自动完成后失去焦点:1. 本地验证格式;2.服务器检查用户是否注册;3.检查验证用户次数
mailAc($accountInput1, function() {
return currentLogin.validateAccountLocal().then(function() {
return currentLogin.validateAccountAsync().always(checkUserAuthCountAsync);
... ... @@ -879,7 +1003,7 @@ $captchaImgWrapper.on('click', '.change-captcha, .captcha-img', function() {
});
// 切换登录模式:密码登录和短信登录
$switchLoginType.on('click', 'div', function() {
$switchPhoneLoginType.on('click', 'div', function() {
var $this = $(this),
type = $this.data('type');
... ... @@ -896,7 +1020,7 @@ $switchLoginType.on('click', 'div', function() {
$(AccountLoginType[type].hideEle).addClass('hide');
});
// 切换登录模式:帐号登录和二维码登录
// 切换登录模式:手机登录和二维码登录
$switchDeviceType.on('click', function() {
var $this = $(this),
$parent = $this.parent(),
... ... @@ -912,23 +1036,34 @@ $switchDeviceType.on('click', function() {
$parent.find('#device-tip').html(DeviceLoginType[type].tipText);
if (type === 'DesktopLogin') {
desktopShowOnce.fire();
desktopTipShowOnce.fire();
clearTimerQrCode();
accountChangeLoginTypeEvent.fire('PasswordLogin');
} else {
mobileShowOnce.fire();
mobileTipShowOnce.fire();
timerCheckQrCodeAsync();
accountChangeLoginTypeEvent.fire('QRCodeLogin');
refreshQrCode(); // 生成二维码
}
});
$qrCodeContainer.on('mouseenter', function() {
console.log('enter');
}).on('mouseleave', function() {
console.log('leave');
$qrCodeOverlay.addClass('qrcode-overlay-helper');
});
$qrCodeOverlay.on('mouseleave', function() {
$qrCodeOverlay.removeClass('qrcode-overlay-helper');
});
$qrCodeOverlay.on('click', '#qrcode-refresh-btn', function() {
refreshQrCode();
});
/** ************************************************************************/
/* 登录 */
/** ************************************************************************/
// click登录
// click登录
$('#login-btn').on('click', login);
// enter登录
... ... @@ -942,8 +1077,8 @@ $('input.va').on('keypress', function(e) {
/* 初始化 */
/** ************************************************************************/
// 初始化为密码登录
accountChangeLoginTypeEvent.fire('PasswordLogin');
// 初始化为桌面登录
$switchDeviceType.triggerHandler('click');
// 只带账户名的页面,密码输入获得焦点
if (($accountInput1.val() !== '' || $accountInput1.val() === $accountInput1.attr('placeholder')) &&
... ... @@ -955,10 +1090,4 @@ if (($accountInput1.val() !== '' || $accountInput1.val() === $accountInput1.attr
/* 结束 */
/** ************************************************************************/
$('.qrcode').qrcode({
render: 'table',
size: 150,
text: getQrCodeVal()
});
$switchDeviceType.triggerHandler('click');
... ...
... ... @@ -265,16 +265,54 @@
}
.qrcode {
height: 150px;
width: 150px;
height: 140px;
width: 140px;
margin: 0 auto;
}
.qrcode-overlay {
position: absolute;
background-color: white;
top: 0;
width: 296px;
height: 160px;
}
.qrcode-overlay-helper {
position: absolute;
background: url(/passport/qrcode-example.png) no-repeat !important;
top: 0;
width: 296px;
height: 160px;
}
.qrcode-overlay-success {
position: absolute;
background: url(/passport/qrcode-success.png) no-repeat !important;
top: 0;
width: 140px;
height: 140px;
}
.qrcode-overlay-fail {
position: absolute;
background: url(/passport/qrcode-blank.png) no-repeat !important;
top: 0;
left: 65px;
width: 140px;
height: 140px;
}
.qrcode-login-title {
margin-bottom: 50px !important;
margin-bottom: 40px !important;
font-weight: bold;
}
.qrcode-err-tip {
margin-top: 50px ;
margin-bottom: 10px;
font-weight: bold;
font-size: 13px;
}
.tip-title {
... ... @@ -282,4 +320,16 @@
font-size: 13px;
}
.qrcode-refresh-btn {
color: white;
display: block;
width: 85px;
height: 30px;
background-color: red;
margin: 0 auto;
font-size: 13px;
line-height: @height;
cursor: pointer;
border-radius:5px
}
}
... ...