소스 검색

用户相关

kphcdr 1 년 전
부모
커밋
60c6fd9e77

+ 38 - 0
app/Http/Middleware/MiniAuthMiddleware.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use App\Models\User\User;
+use App\Modules\Admin\Services\AuthService;
+use Closure;
+use Illuminate\Auth\AuthenticationException;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class MiniAuthMiddleware
+{
+    public function handle(Request $request, Closure $next)
+    {
+        $token = $request->header('Authorization');
+        if (empty($token)) {
+            throw new AuthenticationException("need authorization");
+        }
+        $uid = app(AuthService::class)->decryptToken(substr($token, 7));
+
+        $u = User::find($uid);
+        if (is_null($u)) {
+            return response()->json([
+                "code" => 401,
+            ]);
+        }
+        Auth::login($u);
+
+        logger()->info("mini operation log", [
+            "url" => $request->url(),
+            "method" => $request->method(),
+            "request" => $request->all(),
+        ]);
+
+        return $next($request);
+    }
+}

+ 4 - 0
app/Models/User/User.php

@@ -33,6 +33,10 @@ use Illuminate\Auth\Authenticatable;
  * @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value)
  * @mixin \Eloquent
  * @property-read \App\Models\User\UserCompany|null $company
+ * @property string $openid 微信openid
+ * @method static \Illuminate\Database\Eloquent\Builder|User whereOpenid($value)
+ * @property string $name 用户昵称
+ * @method static \Illuminate\Database\Eloquent\Builder|User whereName($value)
  */
 class User extends BaseModel implements \Illuminate\Contracts\Auth\Authenticatable
 {

+ 5 - 0
app/Modules/Admin/Services/AuthService.php

@@ -22,6 +22,11 @@ class AuthService extends BaseService
         if ($u->status != User::STATUS_OK) {
             throw new ClientException("当前用户被禁用,请联系管理员");
         }
+
+        if (!$u->group_id) {
+            throw new ClientException("无权限");
+        }
+
         return [
             "admin_token" => $this->encryptToken($u->id),
         ];

+ 24 - 8
app/Modules/Mini/Controllers/AuthController.php

@@ -3,27 +3,43 @@
 namespace App\Modules\Mini\Controllers;
 
 use App\Base\BaseController;
+use App\Models\User\User;
+use App\Modules\Mini\Services\AuthService;
+use App\Modules\Mini\Services\WechatService;
 use Faker\Provider\Image;
 
 class AuthController extends BaseController
 {
     public function codeToSession()
     {
+        $params = $this->valid([
+            "code" => "required",
+        ]);
+
+        $sessionData = app(WechatService::class)->codeToSession($params['code']);
+        $token = app(AuthService::class)->authByOpenid($sessionData['openid']);
+
         return $this->ok([
-            "openid" => "openid",
-            "session_key" => "session_key",
-            "token" => "token",
-            "name" => "",
-            "phone" => "",
+            "token" => $token,
+            "openid" => $sessionData['openid'],
+            "sessionKey" => $sessionData['session_key'],
         ]);
     }
 
     public function decryptUserInfo()
     {
+        $params = $this->valid([
+            "iv" => "required",
+            "encrypted_data" => "required",
+            "session_key" => "required",
+        ]);
+        app(WechatService::class)->decryptUserInfo($params);
+        /** @var User $user */
+        $user = \Auth::user();
         return $this->ok([
-            "token" => "token",
-            "name" => "",
-            "phone" => "",
+            "token" => app(AuthService::class)->encryptToken($user->id),
+            "name" => $user->name,
+            "phone" => $user->phone,
         ]);
     }
 

+ 34 - 0
app/Modules/Mini/Services/AuthService.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Modules\Mini\Services;
+
+use App\Base\BaseService;
+use App\Exceptions\ClientException;
+use App\Models\User\User;
+use EasyWeChat\Kernel\HttpClient\Response;
+use EasyWeChat\MiniApp\Application;
+
+class AuthService extends BaseService
+{
+    public function authByOpenid($openId): string
+    {
+        $user = User::where('openid', $openId)->first();
+        if (is_null($user)) {
+            $user = new User();
+            $user->openid = $openId;
+            $user->save();
+        }
+
+        return $this->encryptToken($user->id);
+    }
+
+    public function encryptToken($uid)
+    {
+        return md5($uid) . $uid;
+    }
+
+    public function decryptToken($token)
+    {
+        return substr($token, 32);
+    }
+}

+ 92 - 0
app/Modules/Mini/Services/WechatService.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace App\Modules\Mini\Services;
+
+use App\Base\BaseService;
+use App\Exceptions\ClientException;
+use App\Models\User\User;
+use EasyWeChat\Kernel\HttpClient\Response;
+use EasyWeChat\MiniApp\Application;
+
+class WechatService extends BaseService
+{
+    protected $config;
+
+    /**
+     * @param $config
+     */
+    public function __construct()
+    {
+        $this->config = config('account.wechat.mini_app');
+    }
+
+    public function decryptUserInfo($params)
+    {
+        $data = $this->wechat()->getUtils()->decryptSession($params['session_key'], $params['iv'], $params['encrypted_data']);
+//{
+//    "openId": "oGZUI0egBJY1zhBYw2KhdUfwVJJE",
+//    "nickName": "Band",
+//    "gender": 1,
+//    "language": "zh_CN",
+//    "city": "Guangzhou",
+//    "province": "Guangdong",
+//    "country": "CN",
+//    "avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0",
+//    "unionId": "ocMvos6NjeKLIBqg5Mr9QjxrP1FA",
+//    "watermark": {
+//        "timestamp": 1477314187,
+//        "appid": "wx4f4bc4dec97d474b"
+//    }
+//}
+        /** @var User $user */
+        $user = \Auth::user();
+        if (is_null($user)) {
+            throw new ClientException("need Authentication");
+        }
+        $user->name = $data['nickName'];
+        $user->extra = array_merge($user->extra, [
+            "wechatdata" => $data,
+        ]);
+        $user->save();
+    }
+
+    /**
+     * @return Application
+     */
+    private function wechat()
+    {
+        return new Application($this->config);
+    }
+
+    /**
+     * @see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
+     */
+    public function codeToSession($code)
+    {
+
+        $options = [
+            'query' => [
+                'appid' => $this->config['app_id'],
+                'js_code' => $code,
+                'secret' => $this->config['secret'],
+                "grant_type" => "authorization_code",
+            ],
+        ];
+        return $this->render($this->wechat()->getClient()->get("/sns/jscode2session", $options));
+    }
+
+    /**
+     * @param Response $resp
+     */
+    private function render($resp)
+    {
+        if ($resp->isFailed()) {
+            logger()->error("wechat render failer", [
+                "resp" => $resp->getContent(),
+            ]);
+            throw new ClientException("调用微信接口出错,请稍后再试");
+        }
+
+        return json_decode($resp->getContent(), true);
+    }
+}

+ 2 - 2
composer.json

@@ -10,8 +10,8 @@
         "guzzlehttp/guzzle": "^7.2",
         "laravel/framework": "^9.19",
         "laravel/tinker": "^2.7",
-        "overtrue/laravel-wechat": "^7.2",
-        "th3n3rd/cartesian-product": "^0.3.0"
+        "th3n3rd/cartesian-product": "^0.3.0",
+        "w7corp/easywechat": "^6.8"
     },
     "require-dev": {
         "barryvdh/laravel-ide-helper": "^2.12",

+ 1 - 81
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "dd7b494ce3580c3bdbb2d303211320a7",
+    "content-hash": "320f59e9a21e1e21120a39076a4f693a",
     "packages": [
         {
             "name": "brick/math",
@@ -2743,86 +2743,6 @@
             "time": "2021-05-12T11:11:27+00:00"
         },
         {
-            "name": "overtrue/laravel-wechat",
-            "version": "7.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/overtrue/laravel-wechat.git",
-                "reference": "2ef8b18b525e054838770c60bfcfbd30ac9ede65"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/overtrue/laravel-wechat/zipball/2ef8b18b525e054838770c60bfcfbd30ac9ede65",
-                "reference": "2ef8b18b525e054838770c60bfcfbd30ac9ede65",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
-            },
-            "require": {
-                "illuminate/container": "^9.0|^10.0",
-                "w7corp/easywechat": "^6.0.0"
-            },
-            "require-dev": {
-                "brainmaestro/composer-git-hooks": "dev-master",
-                "jetbrains/phpstorm-attributes": "^1.0",
-                "laravel/framework": "^10.0",
-                "laravel/pint": "^1.5"
-            },
-            "type": "library",
-            "extra": {
-                "laravel": {
-                    "providers": [
-                        "Overtrue\\LaravelWeChat\\ServiceProvider"
-                    ]
-                },
-                "hooks": {
-                    "pre-commit": [
-                        "composer check-style"
-                    ],
-                    "pre-push": [
-                        "composer check-style"
-                    ]
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Overtrue\\LaravelWeChat\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "overtrue",
-                    "email": "anzhengchao@gmail.com"
-                }
-            ],
-            "description": "微信 SDK for Laravel",
-            "keywords": [
-                "laravel",
-                "sdk",
-                "wechat",
-                "weixin"
-            ],
-            "support": {
-                "issues": "https://github.com/overtrue/laravel-wechat/issues",
-                "source": "https://github.com/overtrue/laravel-wechat/tree/7.2.0"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/overtrue",
-                    "type": "github"
-                }
-            ],
-            "time": "2023-02-15T08:16:22+00:00"
-        },
-        {
             "name": "overtrue/socialite",
             "version": "4.8.0",
             "source": {

+ 12 - 0
config/account.php

@@ -0,0 +1,12 @@
+<?php
+
+return [
+    "wechat" => [
+        'mini_app' => [
+            'app_id' => env('WECHAT_MINI_APP_APPID', 'wx16e755a7f4e33845'),
+            'secret' => env('WECHAT_MINI_APP_SECRET', '7e88c7cdb73ed81dd62a3d8c07a85333'),
+            'token' => env('WECHAT_MINI_APP_TOKEN', ''),
+            'aes_key' => env('WECHAT_MINI_APP_AES_KEY', ''),
+        ],
+    ],
+];

+ 0 - 169
config/easywechat.php

@@ -1,169 +0,0 @@
-<?php
-
-return [
-    /*
-     * 默认配置,将会合并到各模块中
-     */
-    'defaults' => [
-        'http' => [
-            'timeout' => 5.0,
-        ],
-    ],
-
-    /*
-     * 公众号
-     */
-    'official_account' => [
-        'default' => [
-            'app_id' => env('WECHAT_OFFICIAL_ACCOUNT_APPID', ''),     // AppID
-            'secret' => env('WECHAT_OFFICIAL_ACCOUNT_SECRET', ''),    // AppSecret
-            'token' => env('WECHAT_OFFICIAL_ACCOUNT_TOKEN', ''),     // Token
-            'aes_key' => env('WECHAT_OFFICIAL_ACCOUNT_AES_KEY', ''),   // EncodingAESKey
-
-            /*
-             * OAuth 配置
-             *
-             * scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
-             * callback:OAuth授权完成后的回调页地址(如果使用中间件,则随便填写。。。)
-             * enforce_https:是否强制使用 HTTPS 跳转
-             */
-            // 'oauth'   => [
-            //     'scopes'        => array_map('trim', explode(',', env('WECHAT_OFFICIAL_ACCOUNT_OAUTH_SCOPES', 'snsapi_userinfo'))),
-            //     'callback'      => env('WECHAT_OFFICIAL_ACCOUNT_OAUTH_CALLBACK', '/examples/oauth_callback.php'),
-            //     'enforce_https' => true,
-            // ],
-
-            /**
-             * 接口请求相关配置,超时时间等,具体可用参数请参考:
-             * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
-             */
-            //'http' => [
-            //  'timeout' => 5.0,
-            //   // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
-            //  'base_uri' => 'https://api.weixin.qq.com/',
-            //],
-        ],
-    ],
-
-    /*
-     * 开放平台第三方平台
-     */
-    // 'open_platform' => [
-    //     'default' => [
-    //         'app_id'     => env('WECHAT_OPEN_PLATFORM_APPID', ''),
-    //         'secret'     => env('WECHAT_OPEN_PLATFORM_SECRET', ''),
-    //         'token'      => env('WECHAT_OPEN_PLATFORM_TOKEN', ''),
-    //         'aes_key'    => env('WECHAT_OPEN_PLATFORM_AES_KEY', ''),
-
-    /**
-     * 接口请求相关配置,超时时间等,具体可用参数请参考:
-     * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
-     */
-    //          'http' => [
-    //            'timeout' => 5.0,
-    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
-    //            'base_uri' => 'https://api.weixin.qq.com/',
-    //          ],
-    //     ],
-    // ],
-
-    /*
-     * 小程序
-     */
-    'mini_app' => [
-        'default' => [
-            'app_id' => env('WECHAT_MINI_APP_APPID', 'wx16e755a7f4e33845'),
-            'secret' => env('WECHAT_MINI_APP_SECRET', '7e88c7cdb73ed81dd62a3d8c07a85333'),
-            'token' => env('WECHAT_MINI_APP_TOKEN', ''),
-            'aes_key' => env('WECHAT_MINI_APP_AES_KEY', ''),
-        ],
-    ],
-    /**
-     * 接口请求相关配置,超时时间等,具体可用参数请参考:
-     * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
-     */
-    //          'http' => [
-    //            'timeout' => 5.0,
-    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
-    //            'base_uri' => 'https://api.weixin.qq.com/',
-    //          ],
-    //     ],
-    // ],
-
-    /*
-     * 微信支付
-     */
-    // 'pay' => [
-    //     'default' => [
-    //         'app_id'             => env('WECHAT_PAY_APPID', ''),
-    //         'mch_id'             => env('WECHAT_PAY_MCH_ID', 'your-mch-id'),
-    //         'private_key'        => '/data/private/certs/apiclient_key.pem',
-    //         'certificate'        => '/data/private/certs/apiclient_cert.pem',
-    //         'notify_url'         => 'http://example.com/payments/wechat-notify',                           // 默认支付结果通知地址
-    //          /**
-    //           * 证书序列号,可通过命令从证书获取:
-    //           * `openssl x509 -in application_cert.pem -noout -serial`
-    //           */
-    //          'certificate_serial_no' => '6F2BADBE1738B07EE45C6A85C5F86EE343CAABC3',
-    //
-    //          'http' => [
-    //              'base_uri' => 'https://api.mch.weixin.qq.com/',
-    //          ],
-    //
-    //          // v2 API 秘钥
-    //          //'v2_secret_key' => '26db3e15cfedb44abfbb5fe94fxxxxx',
-    //
-    //          // v3 API 秘钥
-    //          //'secret_key' => '43A03299A3C3FED3D8CE7B820Fxxxxx',
-    //
-    //          // 注意 此处为微信支付平台证书 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtml
-    //          'platform_certs' => [
-    //              '/data/private/certs/platform_key.pem',
-    //          ],
-    //     ],
-    // ],
-
-    /*
-     * 企业微信
-     */
-    // 'work' => [
-    //     'default' => [
-    //         'corp_id'    => env('WECHAT_WORK_CORP_ID', ''),
-    //         'secret'     => env('WECHAT_WORK_SECRET', ''),
-    //         'token'      => env('WECHAT_WORK_TOKEN', ''),
-    //         'aes_key'    => env('WECHAT_WORK_AES_KEY', ''),
-
-    /**
-     * 接口请求相关配置,超时时间等,具体可用参数请参考:
-     * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
-     */
-    //          'http' => [
-    //            'timeout' => 5.0,
-    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
-    //            'base_uri' => 'https://api.weixin.qq.com/',
-    //          ],
-    //      ],
-    // ],
-
-    /*
-     * 企业微信开放平台
-     */
-    // 'open_work' => [
-    //     'default' => [
-    //         'corp_id'            => env('WECHAT_OPEN_WORK_CORP_ID', ''),
-    //         'provider_secret'    => env('WECHAT_OPEN_WORK_SECRET', ''),
-    //         'token'              => env('WECHAT_OPEN_WORK_TOKEN', ''),
-    //         'aes_key'            => env('WECHAT_OPEN_WORK_AES_KEY', ''),
-
-    /**
-     * 接口请求相关配置,超时时间等,具体可用参数请参考:
-     * https://github.com/symfony/symfony/blob/6.0/src/Symfony/Contracts/HttpClient/HttpClientInterface.php#L26
-     */
-    //          'http' => [
-    //            'timeout' => 5.0,
-    //             // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
-    //            'base_uri' => 'https://api.weixin.qq.com/',
-    //          ],
-    //      ],
-    // ],
-];

+ 6 - 1
database/migrations/2023_04_26_024500_create_user_table.php

@@ -14,13 +14,18 @@ return new class extends Migration {
     {
         Schema::create('user', function (Blueprint $table) {
             $table->id();
+            $table->string("name")->default("")->comment("昵称");
             $table->string("phone")->default("");
             $table->string("password")->default("");
             $table->string("email")->default("");
             $table->unsignedTinyInteger("status")->default(0)->comment("0 禁用 1启用");
             $table->unsignedInteger("group_id")->default(0);
-            $table->string("extra",2000)->default("")->comment("糊屎字段");
+            $table->string("openid")->default("")->comment("微信openid");
+            $table->string("extra", 2000)->default("")->comment("糊屎字段");
             $table->timestamps();
+
+            $table->index("openid");
+            $table->index("email");
         });
 
         Schema::create('admin_group', function (Blueprint $table) {

+ 5 - 3
routes/mini.php

@@ -6,9 +6,11 @@ use Illuminate\Support\Facades\Route;
 Route::get('/', [\App\Http\Controllers\Controller::class, "ping"]);
 
 Route::post("/auth/codeToSession", [\App\Modules\Mini\Controllers\AuthController::class, "codeToSession"]);
-Route::post("/auth/decryptUserInfo", [\App\Modules\Mini\Controllers\AuthController::class, "decryptUserInfo"]);
-Route::post("/auth/decryptPhone", [\App\Modules\Mini\Controllers\AuthController::class, "decryptPhone"]);
-Route::get("/auth/profile", [\App\Modules\Mini\Controllers\AuthController::class, "profile"]);
+Route::middleware([\App\Http\Middleware\MiniAuthMiddleware::class])->group(function () {
+    Route::post("/auth/decryptUserInfo", [\App\Modules\Mini\Controllers\AuthController::class, "decryptUserInfo"]);
+    Route::post("/auth/decryptPhone", [\App\Modules\Mini\Controllers\AuthController::class, "decryptPhone"]);
+    Route::get("/auth/profile", [\App\Modules\Mini\Controllers\AuthController::class, "profile"]);
+});
 
 Route::get("/page/home", [\App\Modules\Mini\Controllers\PageController::class, "home"]);
 Route::get("/page/categoryTree", [\App\Modules\Mini\Controllers\PageController::class, "categoryTree"]);