1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-26 12:23:06 +08:00

Merge branch 'koogua/block-flood-login' into demo

This commit is contained in:
koogua 2021-10-19 20:23:34 +08:00
commit c2c1c9987e
17 changed files with 166 additions and 12 deletions

View File

@ -97,7 +97,7 @@
</div>
</div>
{% set share_url = full_url({'for':'home.share'},{'id':article.id,'type':'article','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':article.id,'type':'article'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -57,7 +57,7 @@
<input type="hidden" name="bind_user_url" value='{{ bind_user_url }}'>
</div>
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -43,7 +43,7 @@
<input type="hidden" name="chapter.learning_url" value="{{ learning_url }}">
</div>
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -43,7 +43,7 @@
<input type="hidden" name="chapter.play_urls" value='{{ chapter.play_urls|json_encode }}'>
</div>
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -94,7 +94,7 @@
</div>
{% set share_url = full_url({'for':'home.share'},{'id':course.id,'type':'course','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':course.id,'type':'course'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -97,7 +97,7 @@
</div>
</div>
{% set share_url = full_url({'for':'home.share'},{'id':question.id,'type':'question','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':question.id,'type':'question'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -96,7 +96,7 @@
</div>
</div>
{% set share_url = full_url({'for':'home.share'},{'id':user.id,'type':'user','referer':auth_user.id}) %}
{% set share_url = full_url({'for':'home.share'},{'id':user.id,'type':'user'}) %}
{% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
<div class="layui-hide">

View File

@ -16,7 +16,7 @@ class AppInfo
protected $link = 'https://koogua.com';
protected $version = '1.4.6';
protected $version = '1.4.7';
public function __get($name)
{

View File

@ -7,6 +7,8 @@
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class UserSession extends Model
{
@ -45,6 +47,13 @@ class UserSession extends Model
*/
public $client_ip = '';
/**
* 删除标识
*
* @var int
*/
public $deleted = 0;
/**
* 过期时间
*
@ -71,6 +80,18 @@ class UserSession extends Model
return 'kg_user_session';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();

View File

@ -7,6 +7,8 @@
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class UserToken extends Model
{
@ -45,6 +47,13 @@ class UserToken extends Model
*/
public $client_ip = '';
/**
* 删除标识
*
* @var int
*/
public $deleted = 0;
/**
* 过期时间
*
@ -71,6 +80,18 @@ class UserToken extends Model
return 'kg_user_token';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();

View File

@ -18,10 +18,26 @@ class UserSession extends Repository
* @param int $userId
* @return ResultsetInterface|Resultset|UserSessionModel[]
*/
public function findByUserId($userId)
public function findUserActiveSessions($userId)
{
return UserSessionModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->andWhere('deleted = 0')
->execute();
}
/**
* @param int $userId
* @param int $minutes
* @return ResultsetInterface|Resultset|UserSessionModel[]
*/
public function findUserRecentSessions($userId, $minutes = 10)
{
$createTime = time() - $minutes * 60;
return UserSessionModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->andWhere('create_time > :create_time:', ['create_time' => $createTime])
->execute();
}

View File

@ -18,11 +18,26 @@ class UserToken extends Repository
* @param int $userId
* @return ResultsetInterface|Resultset|UserTokenModel[]
*/
public function findByUserId($userId)
public function findUserActiveTokens($userId)
{
return UserTokenModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->execute();
}
/**
* @param int $userId
* @param int $minutes
* @return ResultsetInterface|Resultset|UserTokenModel[]
*/
public function findUserRecentTokens($userId, $minutes = 10)
{
$createTime = time() - $minutes * 60;
return UserTokenModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->andWhere('create_time > :create_time:', ['create_time' => $createTime])
->execute();
}
}

View File

@ -79,7 +79,7 @@ class Api extends AuthService
{
$repo = new UserTokenRepo();
$records = $repo->findByUserId($userId);
$records = $repo->findUserActiveTokens($userId);
if ($records->count() == 0) return;

View File

@ -68,7 +68,7 @@ class Home extends AuthService
$repo = new UserSessionRepo();
$records = $repo->findByUserId($userId);
$records = $repo->findUserActiveSessions($userId);
if ($records->count() == 0) return;

View File

@ -12,13 +12,19 @@ use App\Exceptions\Forbidden as ForbiddenException;
use App\Library\Utils\Password as PasswordUtil;
use App\Library\Validators\Common as CommonValidator;
use App\Models\Account as AccountModel;
use App\Models\Client as ClientModel;
use App\Models\User as UserModel;
use App\Repos\Account as AccountRepo;
use App\Repos\User as UserRepo;
use App\Repos\UserSession as UserSessionRepo;
use App\Repos\UserToken as UserTokenRepo;
use App\Traits\Client as ClientTrait;
class Account extends Validator
{
use ClientTrait;
public function checkAccount($name)
{
$account = null;
@ -175,6 +181,34 @@ class Account extends Validator
if ($locked && !$expired) {
throw new ForbiddenException('account.locked');
}
$this->checkFloodLogin($user->id);
}
public function checkFloodLogin($userId)
{
$clientIp = $this->getClientIp();
$clientType = $this->getClientType();
if ($clientType == ClientModel::TYPE_PC) {
$repo = new UserSessionRepo();
$records = $repo->findUserRecentSessions($userId, 10);
} else {
$repo = new UserTokenRepo();
$records = $repo->findUserRecentTokens($userId, 10);
}
if ($records->count() == 0) return;
$clientIps = array_column($records->toArray(), 'client_ip');
$countValues = array_count_values($clientIps);
foreach ($countValues as $ip => $count) {
if ($clientIp == $ip && $count > 4) {
throw new ForbiddenException('account.flood_login');
}
}
}
}

View File

@ -47,6 +47,7 @@ $error['captcha.invalid_code'] = '无效的验证码';
*/
$error['account.not_found'] = '账号不存在';
$error['account.locked'] = '账号被锁定,无法登录';
$error['account.flood_login'] = '帐号泛滥登录';
$error['account.login_pwd_incorrect'] = '登录密码不正确';
$error['account.invalid_login_name'] = '无效的登录名';
$error['account.invalid_email'] = '无效的电子邮箱';

View File

@ -0,0 +1,46 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
use Phinx\Db\Adapter\MysqlAdapter;
use Phinx\Migration\AbstractMigration;
final class V20211019093522 extends AbstractMigration
{
public function up()
{
$this->alterUserSessionTable();
$this->alterUserTokenTable();
}
protected function alterUserSessionTable()
{
$this->table('kg_user_session')
->addColumn('deleted', 'integer', [
'null' => false,
'default' => '0',
'limit' => MysqlAdapter::INT_REGULAR,
'signed' => false,
'comment' => '删除标识',
'after' => 'client_ip',
])->save();
}
protected function alterUserTokenTable()
{
$this->table('kg_user_token')
->addColumn('deleted', 'integer', [
'null' => false,
'default' => '0',
'limit' => MysqlAdapter::INT_REGULAR,
'signed' => false,
'comment' => '删除标识',
'after' => 'client_ip',
])->save();
}
}