afa 5 сар өмнө
parent
commit
d2f5396767

+ 2 - 0
app/api/common.php

@@ -4,3 +4,5 @@ declare (strict_types = 1);
 // 这是自定义的公共文件
 use think\Log;
 
+
+

+ 28 - 7
app/api/controller/Base.php

@@ -5,6 +5,8 @@ namespace app\api\controller;
 use think\exception\HttpResponseException;
 use think\Request;
 use think\Response;
+use app\api\service\auth\MysqlAdapter;
+use think\facade\Cache;
 
 class Base
 {
@@ -18,6 +20,14 @@ class Base
      */
     protected string $responseType = 'json';
 
+     /**
+     * 无需登录的方法,同时也就不需要鉴权了
+     * @var array
+     */
+    protected $noNeedLogin = [];
+
+    //用户信息
+    protected $userinfo =[];
     /**
      * 构造方法
      * @param Request|null $request
@@ -36,14 +46,25 @@ class Base
      */
     protected function _initialize()
     {
-//        //跨域请求检测
-//        check_cors_request();
-//
-//        // 检测IP是否允许
-//        check_ip_allowed();
+      
+        $token=request()->header('token');
+    
+        $actionname = $this->request->action();
+        $noNeedLoginSet=is_string($this->noNeedLogin)?[$this->noNeedLogin]:$this->noNeedLogin;
+        $noNeedLogin = in_array('*',$noNeedLoginSet) || in_array($actionname,$noNeedLoginSet);
 
-        //移除HTML标签
-        //$this->request->filter('trim,strip_tags,htmlspecialchars');
+        //需要登陆
+        if(!$noNeedLogin && !MysqlAdapter::getUserToken($token)){
+            $response = Response::create(__('请先登录!'), 'html', 401);
+            throw new HttpResponseException($response);
+        }
+       
+        //获取用户信息
+        if(!$noNeedLogin) {
+            $this->userinfo = MysqlAdapter::userinfo($token);
+            if(!$this->userinfo) Response::create(__('请先登录!'), 'html', 401);
+            $this->userinfo = Cache::get('user_info_'.$this->userinfo);
+        }
     }
 
     /**

+ 0 - 17
app/api/controller/Test.php

@@ -1,17 +0,0 @@
-<?php
-
-namespace app\api\controller;
-
-use app\common\model\Orders;
-use app\common\service\OrderService;
-
-class Test extends Base
-{
-
-    public function index(){
-      
-        
-        return  $this->error('apiId有误');
-
-    }
-}

+ 54 - 0
app/api/controller/User.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace app\api\controller;
+
+use app\common\model\Orders;
+use app\api\service\auth\ApiAuthService;
+use app\api\validate\User as UserValidate;
+use think\exception\ValidateException;
+use think\Cache;
+
+class User extends Base
+{
+
+    protected $noNeedLogin = ['login'];
+
+
+    public function userinfo(ApiAuthService $authService)
+    {
+      
+        try{
+       
+            
+            dump($this->userinfo);die;
+            $user = $authService->userinfo();
+
+        }catch (ValidateException $e) {
+          
+            return $this->error($e->getError());
+        }catch (\Exception $e){
+            return $this->error($e->getMessage());
+        }
+        return  $this->success('ok', $user);
+    }
+
+
+
+    public function login(ApiAuthService $authService)
+    {
+        $data = $this->request->post();
+        try{
+       
+            validate(UserValidate::class)->scene('login')->check($data);
+
+            $user = $authService->login($data['username'],$data['password']);
+
+        }catch (ValidateException $e) {
+          
+            return $this->error($e->getError());
+        }catch (\Exception $e){
+            return $this->error($e->getMessage());
+        }
+        return  $this->success('ok', $user);
+    }
+}

+ 24 - 40
app/api/middleware/AllowCrossDomain.php

@@ -1,51 +1,35 @@
 <?php
-declare(strict_types=1);
+
 namespace app\api\middleware;
 
-use Closure;
-use think\Config;
-use think\Request;
 use think\Response;
 
-class AllowCrossDomain{
-    
-   
-
-    /**
-     * 允许跨域请求
-     * @access public
-     * @param Request $request
-     * @param Closure $next
-     * @param array   $header
-     * @return Response
-     */
-    public function handle(Request $request, Closure $next, array $header = []): Response
+class AllowCrossDomain
+{
+    public function handle($request, \Closure $next)
     {
-       
-        // 从配置文件中获取允许的域名列表
-        // 允许的源  
-        // 从.env文件读取配置并转换为数组
-        $allowedOriginsStr = env('CORS_ALLOWED_ORIGINS', '');
-        $allowedOrigins = explode(',', $allowedOriginsStr);
-        $origin = $request->header('Origin');
+         // 处理预检请求
+        if ($request->isOptions()) {
+            return response('', 204)
+                ->header([
+                    'Access-Control-Allow-Origin' => '*', // 或具体域名
+                    'Access-Control-Allow-Methods' => 'GET,POST,PUT,DELETE,OPTIONS',
+                    'Access-Control-Allow-Headers' => 'Content-Type,Authorization,Accept-Language',
+                    'Access-Control-Max-Age' => '86400',
+                ]);
+        }
 
-        dump($origin);die;
-        if (in_array($origin, $allowedOrigins)) {
-            header('Access-Control-Allow-Origin: '. $origin);
-        } else {
+        // 继续后续请求
+        $response = $next($request);
 
-            // 处理不允许的来源,例如返回403错误
-            return response()->code(403)->data(['message' => 'Forbidden']);
-        }
-        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
-        header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
-        header('Access-Control-Allow-Credentials: true');
-        if ($request->method() === 'OPTIONS') {
-            return response()->code(204);
-        }
-         
-        
+        // 设置跨域头
+        $response->header([
+            'Access-Control-Allow-Origin' => '*', // 或 'https://sz-test-3.hxiaoju.top'
+            'Access-Control-Allow-Methods' => 'GET,POST,PUT,DELETE,OPTIONS',
+            'Access-Control-Allow-Headers' => 'Content-Type,Authorization,Accept-Language',
+            'Access-Control-Max-Age' => '86400',
+        ]);
 
-        return $next($request)->header($header);
+        return $response;
     }
 }

+ 5 - 5
app/api/route/route.php

@@ -2,18 +2,18 @@
 declare(strict_types=1);
 
 use think\facade\Route;
-
+use app\api\middleware\AllowCrossDomain;
 
 // 定义 API 路由组
 Route::group('user', function () {
 
-      Route::rule('test','test/index','GET|POST');
+     
       Route::rule('login','user/login','POST');
-      Route::rule('getTxhashDetail','transaction/getTxhashDetail','GET|POST');
+      Route::rule('userinfo','user/userinfo','GET|POST');
       Route::rule('createAddress','transaction/createAddress','GET|POST');
 
-    //
-})->middleware(\app\api\middleware\AllowCrossDomain::class);
+
+  })->middleware(AllowCrossDomain::class);
 
 
 

+ 66 - 0
app/api/service/auth/ApiAuthService.php

@@ -0,0 +1,66 @@
+<?php
+declare(strict_types=1);
+namespace app\api\service\auth;
+
+use app\api\service\auth\Adapter;
+use think\facade\Cache;
+use app\common\model\User;
+use app\common\model\UserToken;
+use think\facade\Config;
+
+
+class ApiAuthService 
+{
+    protected $allowFields = ['id', 'nickname', 'mobile', 'avatar', 'balance', 'score'];
+    
+
+    public function userinfo(bool $allinfo = false)
+    {
+       
+    }
+
+    public function logout()
+    {
+        //$this->adapter->logout();
+    }
+
+    public function getToken()
+    {
+        //$usertoken=$this->adapter->getUserToken();
+        //return $usertoken->token;
+    }
+
+    public function login(string $username, string $password)
+    {
+        $token=uuid();
+        $user=User::where('username',$username)->find();
+        if(!$user){
+            throw new \Exception('账号或密码错误');
+        }
+        if($user->password!=md5(md5($password.$user->salt))){
+            throw new \Exception('账号或密码错误');
+        }
+        if($user->status!='normal'){
+            throw new \Exception('账号已经被禁用');
+        }
+        //刷新token
+        $token = MysqlAdapter::login($token, $user);
+        $user->loginfailure = 0;
+        $user->logintime = time();
+        $user->loginip = request()->ip();
+        $user->save();
+
+        Cache::set('user_info_'.$user->id, $user->toArray(), Config::get('app.user_login.keepalive_time'));
+
+        return ['userinfo'=>$user,'token'=>$token];
+    }
+
+   
+
+
+    public function updateToken(int $uid, array $arr)
+    {
+        return UserToken::where('user_id', $uid)->update($arr);
+    }
+
+}

+ 71 - 0
app/api/service/auth/MysqlAdapter.php

@@ -0,0 +1,71 @@
+<?php
+declare(strict_types=1);
+namespace app\api\service\auth;
+
+use think\facade\Cache;
+use app\common\model\UserToken;
+use app\common\model\User;
+use think\facade\Config;
+
+class MysqlAdapter
+{
+    private UserToken $usertoken;
+
+    public function ddddd()
+    {
+       
+        $time=time();
+        $usertoken=UserToken::where(function ($query) use ($token,$time){
+            $token=md5($token);
+            $query->where('token','=',$token);
+            $query->where('expire','>',$time);
+        })->withJoin('user','right')->find();
+        if($usertoken){
+            $auth=Config::get('site.auth');
+            //当登陆时间小于保持登陆时间的一半时,自动续时
+            if($auth['keepalive'] && $usertoken->expire-$time<$auth['keepalive_time']/2){
+                $usertoken->expire=$time+$auth['keepalive_time'];
+                $usertoken->save();
+            }
+            $usertoken->token=$token;
+            $this->usertoken=$usertoken;
+        }
+    }
+
+    public  static function userinfo(string $token):int
+    {
+        return UserToken::where('token',$token)->where('expire','>', time())->value('user_id');
+    }
+
+    public static function getUserToken($token):bool
+    {
+        return boolval(UserToken::where('token',$token)->where('expire','>', time())->order('id','asc')->count());
+    }
+
+    public static function login(string $token,User $user)
+    {
+        $keepalive_time=Config::get('app.user_login.keepalive_time');
+        $token = md5($token);
+        UserToken::create([
+            'token'=> $token ,
+            'user_id'=>$user->id,
+            'expire'=>time()+$keepalive_time
+        ]);
+      
+        $allow_device_num=Config::get('app.user_login.allow_device_num');
+        //如果数据库中保存的设备数大于允许的设备数,如果超出则挤出去最早登陆的设备
+        $time=time();
+        $count=UserToken::where('user_id',$user->id)->where('expire','>',$time)->count();
+        if($count>$allow_device_num){
+            $usertoken=UserToken::where('user_id',$user->id)->where('expire','>',$time)->order('id','asc')->find();
+            $usertoken->delete();
+        }
+
+        return $token ;
+    }
+
+    public function logout()
+    {
+        UserToken::where('token',$this->usertoken->token)->delete();
+    }
+}

+ 2 - 1
app/middleware.php

@@ -7,5 +7,6 @@ return [
     //应用结束
     app\common\middleware\EndApp::class,
 
-    \think\middleware\AllowCrossDomain::class
+    //\think\middleware\AllowCrossDomain::class
+    \app\api\middleware\AllowCrossDomain::class,
 ];

+ 9 - 0
config/app.php

@@ -51,6 +51,15 @@ return [
         '5' => '小红书',
         '6' => '京东',
     ],
+    //用户登录
+    'user_login'=>[
+        //允许同时在线的设备数量
+       'allow_device_num'=>2,
+        //使用期间自动续时
+       'keepalive'=>true,
+        //保持登陆时间,单位秒
+       'keepalive_time'=>24*3600,
+   ],
 
 
 ];

+ 9 - 1
config/cache.php

@@ -24,6 +24,14 @@ return [
             // 序列化机制 例如 ['serialize', 'unserialize']
             'serialize'  => [],
         ],
-        // 更多的缓存连接
+    // 更多的缓存连接
+    'redis'   =>  [
+            // 驱动方式
+            'type'   => 'redis',
+            // 服务器地址
+            'host'       => '127.0.0.1',
+            'port'       => 6379,
+            'password'   => ''
+        ],
     ],
 ];