header('token'); //判断接口是否免登录 $isNotNeedLogin = $request->controllerObject->isNotNeedLogin(); //不直接判断$isNotNeedLogin结果,使不需要登录的接口通过,为了兼容某些接口可以登录或不登录访问 if (empty($token) && !$isNotNeedLogin) { //没有token并且该地址需要登录才能访问 return JsonService::fail('请求参数缺token', [], 0, 0); } $adminInfo = (new AdminTokenCache())->getAdminInfo($token); if (empty($adminInfo) && !$isNotNeedLogin) { //token过期无效并且该地址需要登录才能访问 return JsonService::fail('登录超时,请重新登录', [], -1); } //token临近过期,自动续期 if ($adminInfo) { //获取临近过期自动续期时长 $beExpireDuration = Config::get('project.admin_token.be_expire_duration'); //token续期 if (time() > ($adminInfo['expire_time'] - $beExpireDuration)) { $result = AdminTokenService::overtimeToken($token); //续期失败(数据表被删除导致) if (empty($result)) { return JsonService::fail('登录过期', [], -1); } } } // Active requests compensate missed central revocations within a 30-second cache window. // Local-only unlinked accounts and disabled installations keep their original behavior. if ($adminInfo && !$isNotNeedLogin && \app\adminapi\service\iam\v2\IamV2Client::enabled()) { $binding = \think\facade\Db::name('iam_v2_binding')->where('admin_id', $adminInfo['admin_id'])->find(); if ($binding && $binding['state'] !== 'unlinked') { try { $b = (new \app\adminapi\service\iam\v2\IamV2Manager())->binding((int) $adminInfo['admin_id']); if (($b['binding']['state'] ?? '') !== 'verified' || !($b['access']['allowed'] ?? false) || ($b['employee']['status'] ?? '') !== 'active') { return JsonService::fail('统一账号关联已失效,请重新登录', [], -1); } } catch (\Throwable $e) { return JsonService::fail('统一身份服务暂时不可用,请稍后重试', [], 0); } } } //给request赋值,用于控制器 $request->adminInfo = $adminInfo; $request->adminId = $adminInfo['admin_id'] ?? 0; // 非 root 须绑定企微:免登录接口不拦截(如 getConfig),避免 init 死循环 if (!empty($adminInfo) && LoginLogic::adminMustBindWorkWechat($adminInfo) && !$isNotNeedLogin) { if (!self::isWorkWechatBindExemptAction($request)) { return JsonService::fail( '请先绑定企业微信后再使用系统', [], LoginLogic::CODE_NEED_BIND_WORK_WECHAT, 0 ); } } return $next($request); } private static function isWorkWechatBindExemptAction($request): bool { if (LoginLogic::isWorkWechatBindExemptActionName((string) $request->action())) { return true; } // 与 AuthMiddleware 一致:未绑企微时仍允许打开面诊进度所需只读列表 if ((int) $request->param('progress_board', 0) === 1 && strtolower((string) $request->action()) === 'lists') { $c = strtolower((string) $request->controller()); return in_array($c, ['auth.admin', 'doctor.appointment'], true); } return false; } }