login.js 6.87 KB
/**
 * 登录
 * @author: Bi Kai<kai.bi@yoho.cn>
 * @date: 2016/05/09
 */
'use strict';

const _ = require('lodash');
const passport = require('passport');
const uuid = require('uuid');
const md5 = require('md5');
const cookie = global.yoho.cookie;
const helpers = global.yoho.helpers;
const log = global.yoho.logger;
const config = global.yoho.config;
const cache = global.yoho.cache;
const AuthHelper = require('../models/auth-helper');
const PassportHelper = require('../models/passport-helper');
const loginPage = `${config.siteUrl}/passport/login/index`;

const SIGNIN_LEFT_BANNER_CODE = 'db350894e01e90eac55cd3a13ad77331';

// 第三方登录回调
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.signinByWechat(
                user.nickname, user.openId, user.unionId, user.sourceType, shoppingKey);
        } else {
            signinByOpenID = AuthHelper.signinByOpenID(
                user.nickname, user.openId, user.sourceType, shoppingKey);
        }

        signinByOpenID.then((result) => {
            if (result.code !== 200) {
                return Promise.reject(result);
            }
            if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line
                return helpers.urlFormat('/passport/thirdlogin/index', {
                    openId: user.unionId || 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;
                }).catch(next);
            }
        }).then((redirectTo) => {
            res.redirect(redirectTo);
        }).catch(() => {
            res.redirect(loginPage);
        });
    } else {
        res.redirect(loginPage);
    }
}

const common = {
    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();
    },
    ipFilter: (req, res, next) => {
        let account = req.body.account;
        let ip = req.ip;

        // let errorLoginKey = 'account_errorlogin_' + account;
        let accountKey = 'account_signin_' + account;
        let ipKey = 'ip_signin_' + ip;

        // let errLoginTimes = cache.get(errorLoginKey) || 0;
        let accountTimes = cache.get(accountKey) || 0;
        let ipTimes = cache.get(ipKey) || 0;

        if (accountTimes >= 10) {
            res.json({ code: 400, message: '您的账号已被暂时锁定,请稍后再试', data: '' });
        } else if (ipTimes >= 100) {
            res.json({ code: 400, message: '您尝试的次数过多,账号已被暂时锁定,请稍后再试', data: '' });
        } else {
            return next();
        }
    }
};

const local = {
    loginPage: (req, res) => {
        // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
        res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);

        let bindMobile = _.trim(req.query.bindMobile || '');
        let bindArea = '+' + _.trim(req.query.bindArea || '86');
        let areaArr = PassportHelper.getCountry();
        let areaName = '';

        if (bindArea) {
            let area = areaArr.find((a) => {
                return a.areaCode === bindArea;
            });

            areaName = area ? area.name : '';
        }
        PassportHelper.getLeftBannerAsync(SIGNIN_LEFT_BANNER_CODE).then(cover => {
            res.render('login', {
                loginPage: true,
                passport: {
                    coverHref: cover.url,
                    coverImg: cover.img,
                    countryCode: bindArea,
                    countryName: areaName,
                    countryList: areaArr,
                    forgetPwd: helpers.urlFormat('/passport/back/index'),
                    fastReg: helpers.urlFormat('/reg.html'),
                    weixinLogin: helpers.urlFormat('/passport/autosign/wechat'),
                    weiboLogin: helpers.urlFormat('/passport/autosign/sina'),
                    alipayLogin: helpers.urlFormat('/passport/autosign/alipay'),
                    doubanLogin: helpers.urlFormat('/passport/autosign/douban'),
                    renrenLogin: helpers.urlFormat('/passport/autosign/renren'),
                    bindMobile: bindMobile
                },
                module: 'passport',
                page: 'login',
                title: '用户登录'
            });
        });
    },
    login: (req, res, next) => {
        passport.authenticate('local', (err, user) => {
            if (err) {
                res.json({
                    code: 400,
                    message: err,
                    data: ''
                });
            } else {
                let refer = req.cookies.refer;

                if (refer) {
                    refer = decodeURI(req.cookies.refer);
                } else {
                    refer = `${config.siteUrl}/home`;
                }

                if (/sign|login/.test(refer)) {
                    refer = `${config.siteUrl}/home`;
                }
                user.session = refer;
                user.href = refer;
                AuthHelper.syncUserSession(user.uid, req, res).then(() => {
                    res.json({
                        code: 200,
                        data: user
                    });
                });
            }
        })(req, res, next);
    }
};

const wechat = {
    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);
            }

            doPassportCallback(req, res, next, {
                openId: user._json.openid,
                unionId: user._json.unionid || user.id,
                nickname: user._json.nickname || user.displayName,
                sourceType: 'wechat',
                rawUser: user
            });
        })(req, res, next);
    }
};

exports.common = common;
exports.wechat = wechat;
exports.local = local;