fix(auth): fail closed on token and validation checks
Made-with: Cursor
This commit is contained in:
@@ -284,3 +284,15 @@
|
||||
|
||||
- 自有业务代码已移除 `crmeb\basic\BaseAuth`、`crmeb\basic\BaseController`、加密版权 helper 的直接引用。
|
||||
- 本地 `php think list` 仍受商业授权环境影响,部署前需要在合法授权或目标运行环境完成全量手工回归。
|
||||
|
||||
## 审查修复记录
|
||||
|
||||
### 自动化检查
|
||||
|
||||
| 命令 | 结果 | 备注 |
|
||||
|------|------|------|
|
||||
| `php -l app/common/controller/AppBaseController.php` | 通过 | 修复校验失败未抛异常的问题。 |
|
||||
| `php -l app/services/auth/AccessTokenService.php` | 通过 | 增加账号状态校验回调。 |
|
||||
| `php -l app/services/out/OutAccountServices.php` | 通过 | 刷新 token 时补齐 `auth` claim,并拒绝禁用/删除外部账号。 |
|
||||
| `php -l app/services/kefu/LoginServices.php` | 通过 | 拒绝禁用客服账号 token。 |
|
||||
| `rg "crmeb\\basic\\BaseAuth|crmeb\\basic\\BaseController|app\\(\\)->make\\(BaseAuth::class\\)|__z6uxy|__qsG" pro_v3.5.1 --glob "*.php"` | 通过 | 应用层仍无商业基础类和加密版权 helper 引用。 |
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace app\common\controller;
|
||||
|
||||
use app\Request;
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
@@ -73,6 +74,10 @@ abstract class AppBaseController
|
||||
$validator->message($scene);
|
||||
}
|
||||
|
||||
return $validator->check($data);
|
||||
if (!$validator->check($data)) {
|
||||
throw new ValidateException($validator->getError());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,11 @@ class AccessTokenService
|
||||
*
|
||||
* @param callable $resolver 根据 token 内的 id 读取账号模型或数组
|
||||
* @param callable $authHashResolver 根据账号返回当前有效的 auth hash
|
||||
* @param callable|null $accountValidator 根据账号判断当前 token 是否仍可用
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function parseToken(string $token, string $type, callable $resolver, callable $authHashResolver)
|
||||
public function parseToken(string $token, string $type, callable $resolver, callable $authHashResolver, callable $accountValidator = null)
|
||||
{
|
||||
if (!$token || $token === 'undefined') {
|
||||
throw new AuthException(ApiErrorCode::ERR_LOGIN);
|
||||
@@ -78,6 +79,11 @@ class AccessTokenService
|
||||
throw new AuthException(ApiErrorCode::ERR_LOGIN);
|
||||
}
|
||||
|
||||
if ($accountValidator && !$accountValidator($account)) {
|
||||
$this->clearToken($md5Token, $type);
|
||||
throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
|
||||
}
|
||||
|
||||
if ($auth !== $authHashResolver($account)) {
|
||||
throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ class LoginServices extends BaseServices
|
||||
$token,
|
||||
'kefu',
|
||||
fn($id) => $this->dao->get($id),
|
||||
fn($adminInfo) => md5($adminInfo->password)
|
||||
fn($adminInfo) => md5($adminInfo->password),
|
||||
fn($adminInfo) => $adminInfo->status && $adminInfo->account_status
|
||||
);
|
||||
|
||||
return $adminInfo->hidden(['password', 'ip', 'status']);
|
||||
|
||||
@@ -81,8 +81,9 @@ class OutAccountServices extends BaseServices
|
||||
$adminInfo = $services->parseToken(
|
||||
$token,
|
||||
'out',
|
||||
fn($id) => $this->dao->get($id),
|
||||
fn($adminInfo) => md5($adminInfo->appsecret)
|
||||
fn($id) => $this->dao->getOne(['id' => $id, 'is_del' => 0]),
|
||||
fn($adminInfo) => md5($adminInfo->appsecret),
|
||||
fn($adminInfo) => (int)$adminInfo->status !== 2
|
||||
);
|
||||
|
||||
return $adminInfo->hidden(['appsecret', 'ip', 'status']);
|
||||
@@ -177,7 +178,7 @@ class OutAccountServices extends BaseServices
|
||||
|
||||
CacheService::redisHandler('out')->delete($md5Token);
|
||||
|
||||
$token = $jwtAuth->createToken($id, $type);
|
||||
$token = $jwtAuth->createToken($id, $type, ['auth' => md5($authInfo->appsecret)]);
|
||||
$data['last_time'] = time();
|
||||
$data['ip'] = request()->ip();
|
||||
$this->dao->update($id, $data);
|
||||
|
||||
Reference in New Issue
Block a user