<?php
namespace AppBundle\Controller;
use ApiBundle\Api\Exception\ErrorCode;
use AppBundle\Common\ArrayToolkit;
use AppBundle\Common\Exception\RuntimeException;
use AppBundle\Component\OAuthClient\OAuthClientFactory;
use Biz\Common\BizSms;
use Biz\Sms\Service\SmsService;
use Common\Exception\BizSmsException;
use CorporateTrainingBundle\System;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Security;
class LoginController extends BaseController
{
public function indexAction(Request $request)
{
$_target_path = $this->getTargetPath($request);
$user = $this->getCurrentUser();
if ($user->isLogin()) {
return $this->createMessageResponse('info', 'login.message.repeat_login', null, 3000, $_target_path);
}
$error = $this->checkLoginError($request);
if ($error) {
$request->getSession()->remove(Security::AUTHENTICATION_ERROR);
} else {
$url = $this->checkInviteCodeLogin($request);
if (!empty($url)) {
return $this->redirect($url);
}
}
$this->callRemoteService($request, $user);
$liveLogin = $this->checkLiveLogin($request, $_target_path);
return $this->render(
'login/index.html.twig',
[
'last_username' => $request->getSession()->get(Security::LAST_USERNAME),
'error' => $error,
'_target_path' => $_target_path,
'liveLogin' => $liveLogin,
'sms_login_open' => $this->getSmsService()->isOpen(BizSms::SMS_LOGIN),
]
);
}
protected function callRemoteService(Request $request, $user)
{
if (in_array('ROLE_SUPER_ADMIN', $user['roles'])) {
$siteInfo = $this->getSettingService()->get('site_info', []);
if (!empty($siteInfo) && false == $siteInfo['status']) {
$siteInfo['applicationVersion'] = System::CT_VERSION;
$siteInfo['domainName'] = $request->getHttpHost();
if (empty($siteInfo['cloud_key'])) {
$settings = $this->getSettingService()->get('storage', []);
if (!empty($settings['cloud_access_key'])) {
$siteInfo['accessKey'] = $settings['cloud_access_key'];
$this->postRequest('http://ct.edusoho.com/api/app_install', json_encode($siteInfo));
}
}
}
}
}
public function externalLoginAction(Request $request, RouterInterface $router)
{
// 新增开关校验
$setting = $this->getSettingService()->get('api');
if (empty($setting['external_switch'])) {
throw new BadRequestHttpException('API设置未开启', null, ErrorCode::INVALID_ARGUMENT);
}
$token = $request->get('token', '');
if (!$token) {
throw new BadRequestHttpException('请求参数错误', null, ErrorCode::INVALID_ARGUMENT);
}
$goto = $this->parseGoto($request->get('goto', ''), $router);
$data = JWT::decode($token, new Key($setting['api_app_secret_key'], 'HS256'));
if (empty($data) || empty($data->identifyValue) || empty($data->identifyType) || !in_array($data->identifyType, ['username', 'mobile', 'email'])) {
throw new BadRequestHttpException('请求参数错误', null, ErrorCode::INVALID_ARGUMENT);
}
$user = $this->getUserService()->getUserByLoginTypeAndField($data->identifyType, $data->identifyValue);
if (empty($user)) {
return $this->createMessageResponse('error', 'external.login.message.error', null, 0);
}
$this->authenticateUser($user);
return $this->redirect(empty($goto) ? $this->generateUrl('homepage') : $goto);
}
protected function parseGoto(string $goto, RouterInterface $router)
{
if (empty($goto)) {
return $goto;
}
$goto = urldecode($goto);
$parsedGoto = parse_url($goto);
if (isset($parsedGoto['scheme']) || isset($parsedGoto['host'])) {
throw new BadRequestHttpException('跳转地址错误', null, ErrorCode::INVALID_ARGUMENT);
}
$path = $parsedGoto['path'] ?? '';
if (empty($path)) {
return $path;
}
try {
// 验证路径是否匹配有效路由
$router->match($path);
} catch (ResourceNotFoundException $e) {
throw new BadRequestHttpException('跳转地址无效', null, ErrorCode::INVALID_ARGUMENT);
}
return $goto;
}
protected function checkLiveLogin(Request $request, &$_target_path)
{
$liveLogin = preg_match('/\/live\/(.*?)\/(.*)/', $_target_path, $match);
if ($liveLogin && in_array($match[2], ['login', 'entry', 'show', 'replay'])) {
$_target_path = $this->generateUrl('live_activity_play', ['activityId' => $match[1]]);
}
return $liveLogin ? $match[1] : 0;
}
public function ajaxAction(Request $request)
{
$clients = OAuthClientFactory::clients();
return $this->render('login/ajax.html.twig', [
'_target_path' => $this->getTargetPath($request),
'clients' => $clients,
]);
}
public function oauth2LoginsBlockAction($targetPath, $displayName = true, $isMayday = 0)
{
$clients = OAuthClientFactory::clients();
return $this->render('login/oauth2-logins-block.html.twig', [
'clients' => $clients,
'targetPath' => $targetPath,
'displayName' => $displayName,
'isMayday' => $isMayday,
]);
}
public function smsAction(Request $request)
{
$user = $this->getCurrentUser();
if ($user->isLogin()) {
return $this->createMessageResponse('info', '你已经登录了', null, 3000, $this->getTargetPath($request));
}
if ($request->isMethod('POST')) {
$mobile = $request->request->get('login_mobile');
$smsToken = $request->request->get('sms_token');
$smsCode = $request->request->get('login_sms_code');
if (empty($mobile) || empty($smsToken) || empty($smsCode)) {
return $this->createJsonResponse(['error' => ['message' => 'sms.code.invalid']], 400);
}
$result = $this->getBizSms()->check(BizSms::SMS_LOGIN, $mobile, $smsToken, $smsCode);
if (BizSms::STATUS_INVALID === $result) {
return $this->createJsonResponse(['error' => ['message' => 'sms.code.invalid']], 400);
}
if (BizSms::STATUS_EXPIRED === $result) {
return $this->createJsonResponse(['error' => ['message' => 'sms.code.expired']], 400);
}
// 按手机号获取用户,没有就注册
$user = $this->getUserService()->getUserByVerifiedMobile($mobile);
if (empty($user)) {
throw new RuntimeException('该手机账号不存在');
}
if ($user['locked']) {
throw new RuntimeException('该用户已被封禁!');
}
$this->authenticateUser($user);
$goto = $this->getTargetPath($request);
if (empty($goto) || $goto === 'undefined') {
$goto = '/';
}
return $this->createJsonResponse(['goto' => $goto]);
}
return $this->render('login/sms.html.twig', [
'_target_path' => $this->getTargetPath($request),
]);
}
protected function checkInviteCodeLogin(Request $request)
{
if ($this->getWebExtension()->isMicroMessenger() && $this->setting('login_bind.enabled', 0) && $this->setting('login_bind.weixinmob_enabled', 0)) {
$inviteCode = $request->query->get('inviteCode', '');
return $this->generateUrl('login_bind', ['type' => 'weixinmob', '_target_path' => $this->getTargetPath($request), 'inviteCode' => $inviteCode]);
}
if ($this->getCTWebExtension()->isDingTalk() && $this->setting('login_bind.enabled', 0) && $this->setting('login_bind.dingtalkmob_enabled', 0)) {
$inviteCode = $request->query->get('inviteCode', '');
return $this->generateUrl('login_bind', ['type' => 'dingtalkmob', '_target_path' => $this->getTargetPath($request), 'inviteCode' => $inviteCode]);
}
if ($this->getCTWebExtension()->isWorkWechat() && $this->setting('login_bind.enabled', 0) && $this->setting('login_bind.workwechatmob_enabled', 0)) {
$inviteCode = $request->query->get('inviteCode', '');
return $this->generateUrl('login_bind', ['type' => 'workwechatmob', '_target_path' => $this->getTargetPath($request), 'inviteCode' => $inviteCode]);
}
if ($this->getCTWebExtension()->isFeiShu() && $this->setting('login_bind.enabled', 0) && $this->setting('login_bind.feishumob_enabled', 0)) {
$inviteCode = $request->query->get('inviteCode', '');
return $this->generateUrl('login_bind', ['type' => 'feishumob', '_target_path' => $this->getTargetPath($request), 'inviteCode' => $inviteCode]);
}
return 0;
}
protected function getCTWebExtension()
{
return $this->container->get('corporatetrainingbundle.twig.web_extension');
}
protected function checkLoginError(Request $request)
{
if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
return $request->attributes->get(Security::AUTHENTICATION_ERROR);
}
return $request->getSession()->get(Security::AUTHENTICATION_ERROR);
}
protected function checkSmsCode(Request $request)
{
$fields = $request->request->all();
if (!ArrayToolkit::requireds($fields, ['login_mobile', 'sms_token', 'login_sms_code'])) {
return false;
}
$result = $this->getBizSms()->checkAndGetMessage(
BizSms::SMS_LOGIN,
$fields['login_mobile'],
$fields['sms_token'],
$fields['login_sms_code']
);
return $result['success'];
}
protected function getSmsCodeErrorMessage($result)
{
if ($result['success']) {
return null;
}
return $result['message'];
}
/**
protected function getTargetPath(Request $request)
{
if ($request->query->get('goto')) {
$targetPath = $request->query->get('goto');
} elseif ($request->getSession()->has('_target_path')) {
$targetPath = $request->getSession()->get('_target_path');
} elseif ($request->request->get('_target_path')) {
$targetPath = $request->request->get('_target_path');
} else {
$targetPath = $request->headers->get('Referer', '');
}
if (empty($targetPath)) {
return $this->generateUrl('homepage');
}
if ($targetPath == $this->generateUrl('login', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
return $this->generateUrl('homepage');
}
$url = explode('?', $targetPath);
if ($url[0] == $this->generateUrl('partner_logout', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
return $this->generateUrl('homepage');
}
if ($url[0] == $this->generateUrl('password_reset_update', [], UrlGeneratorInterface::ABSOLUTE_URL)) {
$targetPath = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
}
if (0 === strpos($targetPath, '/app.php')) {
$targetPath = str_replace('/app.php', '', $targetPath);
}
return $targetPath;
}
protected function getWebExtension()
{
return $this->container->get('web.twig.extension');
}
/**
* @return BizSms
*/
protected function getBizSms()
{
$biz = $this->getBiz();
return $biz['biz_sms'];
}
protected function getSettingService()
{
return $this->container->get('biz')->service('System:SettingService');
}
/**
* @return SmsService
*/
protected function getSmsService()
{
return $this->getBiz()->service('Sms:SmsService');
}
}