diff --git a/app/Http/Home/Views/article/show.volt b/app/Http/Home/Views/article/show.volt
index 62fa935f..9941b176 100644
--- a/app/Http/Home/Views/article/show.volt
+++ b/app/Http/Home/Views/article/show.volt
@@ -97,7 +97,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/chapter/live/active.volt b/app/Http/Home/Views/chapter/live/active.volt
index 82cd87ee..663240e9 100644
--- a/app/Http/Home/Views/chapter/live/active.volt
+++ b/app/Http/Home/Views/chapter/live/active.volt
@@ -57,7 +57,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/chapter/read.volt b/app/Http/Home/Views/chapter/read.volt
index 746a7bb0..0813b106 100644
--- a/app/Http/Home/Views/chapter/read.volt
+++ b/app/Http/Home/Views/chapter/read.volt
@@ -43,7 +43,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/chapter/vod.volt b/app/Http/Home/Views/chapter/vod.volt
index 5c5953f1..1b054626 100644
--- a/app/Http/Home/Views/chapter/vod.volt
+++ b/app/Http/Home/Views/chapter/vod.volt
@@ -43,7 +43,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/course/show.volt b/app/Http/Home/Views/course/show.volt
index 5f6ee021..a9472cb7 100644
--- a/app/Http/Home/Views/course/show.volt
+++ b/app/Http/Home/Views/course/show.volt
@@ -94,7 +94,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/question/show.volt b/app/Http/Home/Views/question/show.volt
index e7d9f36b..d8b3bbc1 100644
--- a/app/Http/Home/Views/question/show.volt
+++ b/app/Http/Home/Views/question/show.volt
@@ -97,7 +97,7 @@
- {% 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}) %}
diff --git a/app/Http/Home/Views/user/show.volt b/app/Http/Home/Views/user/show.volt
index f39aa5ff..599caf83 100644
--- a/app/Http/Home/Views/user/show.volt
+++ b/app/Http/Home/Views/user/show.volt
@@ -96,7 +96,7 @@
- {% 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}) %}
diff --git a/app/Library/AppInfo.php b/app/Library/AppInfo.php
index fed579d7..184af632 100644
--- a/app/Library/AppInfo.php
+++ b/app/Library/AppInfo.php
@@ -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)
{
diff --git a/app/Models/UserSession.php b/app/Models/UserSession.php
index 5b6074a5..7b55481d 100644
--- a/app/Models/UserSession.php
+++ b/app/Models/UserSession.php
@@ -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();
diff --git a/app/Models/UserToken.php b/app/Models/UserToken.php
index aad991e6..5ddda172 100644
--- a/app/Models/UserToken.php
+++ b/app/Models/UserToken.php
@@ -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();
diff --git a/app/Repos/UserSession.php b/app/Repos/UserSession.php
index 2ea25a8d..26f1b542 100644
--- a/app/Repos/UserSession.php
+++ b/app/Repos/UserSession.php
@@ -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();
}
diff --git a/app/Repos/UserToken.php b/app/Repos/UserToken.php
index d6730027..056d8358 100644
--- a/app/Repos/UserToken.php
+++ b/app/Repos/UserToken.php
@@ -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();
+ }
+
}
diff --git a/app/Services/Auth/Api.php b/app/Services/Auth/Api.php
index a29feb63..bd1534a5 100644
--- a/app/Services/Auth/Api.php
+++ b/app/Services/Auth/Api.php
@@ -79,7 +79,7 @@ class Api extends AuthService
{
$repo = new UserTokenRepo();
- $records = $repo->findByUserId($userId);
+ $records = $repo->findUserActiveTokens($userId);
if ($records->count() == 0) return;
diff --git a/app/Services/Auth/Home.php b/app/Services/Auth/Home.php
index b5ab29d8..455c94a3 100644
--- a/app/Services/Auth/Home.php
+++ b/app/Services/Auth/Home.php
@@ -68,7 +68,7 @@ class Home extends AuthService
$repo = new UserSessionRepo();
- $records = $repo->findByUserId($userId);
+ $records = $repo->findUserActiveSessions($userId);
if ($records->count() == 0) return;
diff --git a/app/Validators/Account.php b/app/Validators/Account.php
index 095bcdfa..91a7b9de 100644
--- a/app/Validators/Account.php
+++ b/app/Validators/Account.php
@@ -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');
+ }
+ }
}
}
diff --git a/config/errors.php b/config/errors.php
index 53a22bf1..35aa2658 100644
--- a/config/errors.php
+++ b/config/errors.php
@@ -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'] = '无效的电子邮箱';
diff --git a/db/migrations/20211019093522.php b/db/migrations/20211019093522.php
new file mode 100644
index 00000000..5946d094
--- /dev/null
+++ b/db/migrations/20211019093522.php
@@ -0,0 +1,46 @@
+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();
+ }
+
+}