Login.php 12 KB
<?php

use Action\WebAction;
use LibModels\Web\Passport\RegData;
use LibModels\Web\Passport\LoginData;
use Passport\PassportModel;
use Configs\ChannelConfig;
use WebPlugin\Helpers;
use WebPlugin\Cache;

/**
 * 登录
 */
class LoginController extends WebAction
{

    /**
     * 登录页
     */
    public function indexAction()
    {
        $this->setTitle('用户登录', true, ' | ');

        // 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
        $this->setCookie('LE'.md5('_LOGIN_EXPIRE'),time() + 1800);
//        $this->setSession('_LOGIN_EXPIRE', time() + 1800);
        // 设置公共的头部        
        $this->setSimpleHeader();

        //从绑定页跳回
        $bindMobile = $this->get('bindMobile', '');
        if ($bindMobile && is_string($bindMobile)) {
            $bindMobile = trim($bindMobile);
        }
        $bindArea = $this->get('bindArea', 0);
        if ($bindArea) {
            $bindArea = '+' . trim($bindArea);
        }

        //登录后跳转页面
        $refer = $this->get('refer', $this->server('HTTP_REFERER', ''));
        //检查refer是否为绝对路径,补www.yohobuy.com
        if (!strstr($refer, 'http')) {
            $refer = SITE_MAIN . $refer;
        }
        if (!empty($refer)) {
            //url编码
            $refer = rawurlencode($refer);
            $this->setCookie('refer', $refer);
        }

        //获取登陆页左侧资源
        $cover = PassportModel::getLeftBanner(PassportModel::SIGNIN_LEFT_BANNER_CODE);
        //区域码
        $areaArr = RegData::getAreasData();
        $areaName = '';
        if ($bindArea) {
            foreach ($areaArr as $k => $v) {
                if ($v['areaCode'] === $bindArea) {
                    $areaArr[$k]['selected'] = true;
                    $areaName = $v['name'];
                    break;
                }
            }
        }

        //整合
        $data = array(
            'loginPage' => true,
            'passport' => array(
                'coverHref' => $cover['url'],
                'coverImg' => empty($cover['img']) ? ChannelConfig::$leftDefaultImg : $cover['img'],
                'countryCode' => $bindArea ? $bindArea : '+86',
                'countryName' => $areaName ? $areaName : '中国',
                'countryList' => $areaArr,
                'forgetPwd' => Helpers::url('/passport/back/index'),
                'fastReg' => Helpers::url('/reg.html'),
                'weixinLogin' => Helpers::url('/passport/autosign/wechat'),
                'qqLogin' => Helpers::url('/passport/autosign/qq'),
                'weiboLogin' => Helpers::url('/passport/autosign/sina'),
                'alipayLogin' => Helpers::url('/passport/autosign/alipay'),
                'doubanLogin' => Helpers::url('/passport/autosign/douban'),
                'renrenLogin' => Helpers::url('/passport/autosign/renren'),
                'bindMobile' => $bindMobile
            ),
        );

        $this->_view->display('index', $data);
    }

    /**
     * 登录操作
     *
     * @param string areaCode 地区编号, 不需要+号
     * @param string account 账号(邮箱或手机号)
     * @param string password 密码
     * @return json
     */
    public function authAction()
    {
        $data = array('code' => 400, 'message' => '您输入的密码及账户名不匹配,是否<a href = "' . Helpers::url('/passport/back/index') . '" target = "_blank">忘记密码?</a>', 'data' => '');
        do {
            /* 判断是不是AJAX请求 */
            if (!$this->isAjax()) {
                break;
            }

            /* 判断参数是否传递 */
            $area = trim($this->post('areaCode', '86'));
            $account = trim($this->post('account'));
            $password = trim($this->post('password'));
            $verifyCode = trim($this->post('captcha'));
            $isRemember = $this->post('isRemember');
            if (!is_numeric($area) || empty($account) || empty($password)) {
                break;
            }

            /* 判断参数是否有效 */
            $verifyEmail = Helpers::verifyEmail($account);
            $verifyMobile = Helpers::verifyAreaMobile(Helpers::makeMobile($area, $account));
            if (!$verifyEmail && !$verifyMobile) {
                break;
            }

            /* 设置登录有效时间30分钟, 防机器刷 */
            $expire = $this->getCookie('LE'.md5('_LOGIN_EXPIRE'));
//            $expire = $this->getSession('_LOGIN_EXPIRE');
            if (empty($expire) || $expire < time()) {
                $data = array('code' => 400, 'message' => '页面停留时间过长,请刷新页面', 'data' => '');
                break;
            }

            /* 购物车 */
            $shoppingKey = Helpers::getShoppingKeyByCookie();
            /*
             * 登录-防恶意机制
             * 同一用户名登录密码错误次数超5次,需验证码验证
             * 同一ip登录密码错误次数超5次,需验证码验证
             * 同一用户名登录密码错误次数超10次,需30分钟后尝试
             * 同一ip登录密码错误次数超100次,需1小时后尝试 , ip错误提示语:您尝试的次数过多,账号已被暂时锁定,请稍后再试
             */
            $ip = Helpers::getClientIp();
            $errorLoginKey = 'account_errorlogin_' . $account; //输错3次,需验证码验证
            $accountKey = 'account_signin_' . $account; //输错10次,半小时锁定账户
            $ipKey = 'ip_signin_' . $ip; //ip登录输错100次,锁定1h
            //调用接口前校验次数
            $errLoginTimes = intval(Cache::get($errorLoginKey));
            $accountTimes = intval(Cache::get($accountKey));
            $ipTimes = intval(Cache::get($ipKey));
            if ($ipTimes >= 100) {
                $data = array('code' => 400, 'message' => '您尝试的次数过多,账号已被暂时锁定,请稍后再试', 'data' => '');
                break;
            }
            if ($accountTimes >= 10) {
                $data = array('code' => 400, 'message' => '您的账号已被暂时锁定,请稍后再试', 'data' => '');
                break;
            }

            //调用登录接口前,若含有验证码则后端校验验证码
            if ($verifyCode) {
                $picFlag = PassportModel::verifyCode($verifyCode);
                if (!$picFlag) {
                    $data = array('code' => 400, 'message' => '验证码不正确或验证码已过期', 'data' => array('needCaptcha' => true, 'errorType' => 'captcha'));
                    break;
                }
            }
            $data = LoginData::signin($area, $account, $password, $shoppingKey);
            if (!isset($data['code']) || $data['code'] != 200 || !isset($data['data']['uid'])) {
                $errLoginTimes = $errLoginTimes + 1;
                $accountTimes = $accountTimes + 1;
                $ipTimes = $ipTimes + 1;
                Cache::set($errorLoginKey, $errLoginTimes);
                Cache::set($accountKey, $accountTimes, 1800);
                Cache::set($ipKey, $ipTimes, 3600);
                //再次校验
                if ($ipTimes >= 100) {
                    $data = array('code' => 400, 'message' => '您尝试的次数过多,账号已被暂时锁定,请稍后再试', 'data' => '');
                    break;
                }
                if ($accountTimes >= 10) {
                    $data = array('code' => 400, 'message' => '您的账号已被暂时锁定,请稍后再试', 'data' => '');
                    break;
                }
                if ($errLoginTimes >= 3) {
                    $data = array('code' => 400, 'message' => '您输入的密码及账户名不匹配,是否<a href="' . Helpers::url('/passport/back/index') . '" target="_blank">忘记密码?</a>', 'data' => array('needCaptcha' => true));
                    break;
                }
                $data = array('code' => 400, 'message' => '您输入的密码及账户名不匹配,是否<a href="' . Helpers::url('/passport/back/index') . '" target="_blank">忘记密码?</a>', 'data' => '');
                break;
            }

            //登录成功
            //清除errLoginTimes
            Cache::delete($errorLoginKey);
            //记住登录状态-保存信息
            if ($isRemember == 'true') {
                $accountInfo = array(
                    'area' => trim($area),
                    'account' => trim($account),
                    'password' => trim($password)
                );
                $this->rememberAccount($accountInfo);
            }
            else {
                $this->setCookie('isRemember', false);
                $this->setCookie('remem', '');
            }
            $refer = rawurldecode($this->getCookie('refer'));
            $isRedirectHome = PassportModel::redirectHome($refer);
            if (empty($refer) || $isRedirectHome) {
                $refer = SITE_MAIN;
            }
            $token = Helpers::makeToken($data['data']['uid']);
            $this->setCookie('_TOKEN', $token);
            $this->setSession('_TOKEN', $token);
            $this->setSession('_LOGIN_UID', $data['data']['uid']);
            $data['data']['session'] = Helpers::syncUserSession($data['data']['uid'], $refer);
            $data['data']['href'] = $refer;

            //校验邮箱登录,是否进入绑定手机流程
//            if ($verifyEmail) {
//                $emailBind = PassportModel::emailBindCheck($account);
//                $emailBind = true;
//                if ($emailBind) {
//                    $goUrl = Helpers::syncUserSession($data['data']['uid'], Helpers::url('/passport/autouserinfo/userinfo'));
//                    $data['data']['session'] = $goUrl;
//                    $data['data']['href'] = $goUrl;
//                }
//            }
        }
        while (false);

        $this->echoJson($data);
    }

    /**
     * 根据手机号码判断是否出现验证码
     * 
     */
    public function accountAction()
    {
        $account = $this->get('account');
        $errorLoginKey = 'account_errorlogin_' . $account; //输错3次,需验证码验证   
        $errLoginTimes = Cache::get($errorLoginKey);
        do {
            if (!$this->isAjax()) {
                break;
            }
            if (!empty($errLoginTimes) && $errLoginTimes >= 3) {
                $data = array('code' => 400, 'message' => '', 'data' => array('needCaptcha' => true));
                break;
            }
            $data = array('code' => 400, 'message' => '', 'data' => '');
        }
        while (false);

        $this->echoJson($data);
    }

    //退出
    public function outAction()
    {
        // 清除服务端会话
        $this->setSession('_TOKEN', '');
        $this->setSession('_LOGIN_UID', '');

        // 清除客户端
        $this->setCookie('_UID', '');
        $this->setCookie('_TOKEN', '');
        $this->setCookie('_SPK', '');
        $this->setCookie('_g', '');

        // 清除自动登录状态的相关信息
        $this->setCookie('isRemember', false);
        $this->setCookie('remem', '');

        $refer = $this->server('HTTP_REFERER', SITE_MAIN);
        $token = $this->get('token');
        if (!empty($token)) {
            $this->go(Helpers::logoutSession($token, $refer));
        }

        $this->go($refer);
    }

    /**
     * 保存自动登录账户信息
     */
    protected function rememberAccount($accountInfo)
    {
        $aWeek = time() + 504000; //504000-一周
        $this->setCookie('isRemember', true, $aWeek);
        $rememKey = md5(md5($accountInfo['account'] . $accountInfo['password'] . $accountInfo['area']));
        $this->setCookie('remem', $rememKey, $aWeek);
        if (!Cache::get($rememKey)) {
            Cache::set($rememKey, $accountInfo, $aWeek);
        }
    }

}