|
@@ -8,12 +8,14 @@ use App\Tools\PublicData;
|
|
|
use App\Tools\Result;
|
|
|
use Hyperf\Context\Context;
|
|
|
use PHPStan\Type\Accessory\OversizedArrayType;
|
|
|
+use PHPUnit\Exception;
|
|
|
use function Hyperf\Support\env;
|
|
|
use Hyperf\Di\Annotation\Inject;
|
|
|
use Hyperf\HttpServer\Annotation\AutoController;
|
|
|
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
|
|
|
use \Phper666\JWTAuth\JWT;
|
|
|
use App\Model\UserToken;
|
|
|
+use Hyperf\HttpServer\Response;
|
|
|
/**
|
|
|
* @AutoController()
|
|
|
*/
|
|
@@ -28,6 +30,14 @@ class LoginController extends AbstractController
|
|
|
*/
|
|
|
#[Inject]
|
|
|
private $userServiceClient;
|
|
|
+ /**
|
|
|
+ * @var Response
|
|
|
+ */
|
|
|
+// private $response;
|
|
|
+// public function __construct(Response $response)
|
|
|
+// {
|
|
|
+// $this->response = $response;
|
|
|
+// }
|
|
|
public function login(Jwt $jwt)
|
|
|
{
|
|
|
|
|
@@ -428,12 +438,183 @@ class LoginController extends AbstractController
|
|
|
}else{
|
|
|
$isDel = 1;
|
|
|
}
|
|
|
- $jwt->logout($reqData['token']);
|
|
|
+ try {
|
|
|
+ $jwt->logout($reqData['token']);
|
|
|
+ }catch (\Exception $e){
|
|
|
+ return Result::success(['isDel' => $isDel]);
|
|
|
+ }
|
|
|
return Result::success(['isDel' => $isDel]);
|
|
|
}
|
|
|
|
|
|
public function goLogin()
|
|
|
{
|
|
|
+ // 获取请求数据并设置默认值
|
|
|
+ $reqData = $this->request->all();
|
|
|
+ // 安全过滤 Admin-Token 和 ticket
|
|
|
+ $adminToken = !empty($_COOKIE['Admin-Token']) ? $this->sanitizeInput($_COOKIE['Admin-Token']) : '';
|
|
|
+ $ticket = !empty($reqData['ticket']) ? $this->sanitizeInput($reqData['ticket']) : '';
|
|
|
+ $backurl = $this->sanitizeBackUrl($reqData['backurl'] ?? $_SERVER['HTTP_REFERER'] ?? '');
|
|
|
+
|
|
|
+ // 校验 THE_HOST 环境变量
|
|
|
+ $theHost = env("THE_HOST");
|
|
|
+ if (empty($theHost)) {
|
|
|
+ return Result::error('系统配置错误:THE_HOST 未定义');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果存在 adminToken,则进行登录校验
|
|
|
+ if (!empty($adminToken)) {
|
|
|
+ try {
|
|
|
+ $redis = $this->container->get(\Hyperf\Redis\Redis::class);
|
|
|
+
|
|
|
+ // 如果 ticket 存在且有效,则直接跳转
|
|
|
+ if (!empty($ticket) && $redis->exists('ticket:' . $ticket)) {
|
|
|
+ $this->redirectWithTicket($backurl, $ticket, $adminToken);
|
|
|
+ // return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果 ticket 不存在或无效,则重新生成 ticket 并跳转
|
|
|
+ if (empty($ticket)) {
|
|
|
+ $ticket = md5($adminToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 跳转到目标页面
|
|
|
+ $this->redirectWithTicket($backurl, $ticket, $adminToken);
|
|
|
+ // return;
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ // 记录异常日志
|
|
|
+// \Hyperf\Logger\LoggerFactory::get('default')->error('Redis 操作失败: ' . $e->getMessage());
|
|
|
+ // 捕获 Redis 异常,返回错误信息
|
|
|
+ return Result::error('系统错误:Redis 操作失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果没有 adminToken,则跳转到登录页面
|
|
|
+ $loginUrl = 'http://' . $theHost . '/#/login?backurl=' . urlencode($backurl);
|
|
|
+ return $this->response->redirect($loginUrl, 302);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 安全过滤输入数据
|
|
|
+ * @param string $input
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ private function sanitizeInput(string $input): string
|
|
|
+ {
|
|
|
+ return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验并清理 backurl
|
|
|
+ * @param string $backurl
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ private function sanitizeBackUrl(string $backurl): string
|
|
|
+ {
|
|
|
+ // 解码并去除多余字符
|
|
|
+ $decodedUrl = urldecode($backurl);
|
|
|
+ return filter_var($decodedUrl, FILTER_VALIDATE_URL) ?: '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 跳转到目标页面
|
|
|
+ * @param string $backurl
|
|
|
+ * @param string $ticket
|
|
|
+ * @param string $adminToken
|
|
|
+ */
|
|
|
+ private function redirectWithTicket(string $backurl, string $ticket, string $adminToken)
|
|
|
+ {
|
|
|
+ $backurl = rtrim($backurl, '/');
|
|
|
+ $redirectUrl = $this->fun_http($backurl . '?ticket=' . $ticket . '&admintoken=' . urlencode($adminToken));
|
|
|
+ return $this->response->redirect($redirectUrl, 302);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理 URL
|
|
|
+ * @param string $url
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ private function fun_http(string $url): string
|
|
|
+ {
|
|
|
+ // 确保 URL 以 http 或 https 开头
|
|
|
+ if (!preg_match('/^https?:\/\//i', $url)) {
|
|
|
+ $url = 'http://' . $url;
|
|
|
+ }
|
|
|
+ return $url;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退出
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function logout(Jwt $jwt)
|
|
|
+ {
|
|
|
+ $reqData = $this->request->all();
|
|
|
+ $validator = $this->validationFactory->make(
|
|
|
+ $reqData,
|
|
|
+ [
|
|
|
+ 'backurl' => 'required',
|
|
|
+ 'admintoken' => 'required',
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'backurl.required' => 'backurl不能为空',
|
|
|
+ 'admintoken.required' => 'admintoken不能为空',
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ if ($validator->fails()) {
|
|
|
+ $errorMessage = $validator->errors()->first();
|
|
|
+ return Result::error($errorMessage);
|
|
|
+ }
|
|
|
+ $redis = $this->container->get(\Hyperf\Redis\Redis::class);
|
|
|
+ $ticket = md5($reqData['admintoken']);
|
|
|
+ $isDel = 0;
|
|
|
+ if ($redis->exists('ticket:' . $ticket)) {
|
|
|
+ $res = $redis->del('ticket:' . $ticket);
|
|
|
+ if (!!$res && $res == 1) $isDel = 1;
|
|
|
+ }else{
|
|
|
+ $isDel = 1;
|
|
|
+ }
|
|
|
+ setcookie("Admin-Token", "", time(), "/");
|
|
|
+ try {
|
|
|
+ $jwt->logout($reqData['admintoken']);
|
|
|
|
|
|
+ }catch (\Exception $e){
|
|
|
+ $backurl = $this->fun_http($reqData['backurl']);
|
|
|
+ return $this->response->redirect($backurl, 302);
|
|
|
+ }
|
|
|
+ $backurl = $this->fun_http($reqData['backurl']);
|
|
|
+ return $this->response->redirect($backurl, 302);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 登录回调
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function backlogin()
|
|
|
+ {
|
|
|
+ $reqData = $this->request->all();
|
|
|
+ $validator = $this->validationFactory->make(
|
|
|
+ $reqData,
|
|
|
+ [
|
|
|
+ 'backurl' => 'required',
|
|
|
+ 'token' => 'required',
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'backurl.required' => 'backurl不能为空',
|
|
|
+ 'token.required' => 'token不能为空',
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ if ($validator->fails()) {
|
|
|
+ $errorMessage = $validator->errors()->first();
|
|
|
+ return Result::error($errorMessage);
|
|
|
+ }
|
|
|
+ $redis = $this->container->get(\Hyperf\Redis\Redis::class);
|
|
|
+ $ticket = md5($reqData['token']);
|
|
|
+ $res = $redis->set('ticket:' . $ticket, $reqData['token'], 3600*24);
|
|
|
+ if($res && !empty($ticket)){
|
|
|
+ $url = $reqData['backurl'] . '/?ticket=' . $ticket . '&admintoken=' . urlencode($reqData['token']);
|
|
|
+ $url = $this->fun_http($url);
|
|
|
+ return $this->response->redirect($url, 302);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|