From 10a636f7d58e7e11363e15fa330a251cac38d261 Mon Sep 17 00:00:00 2001 From: jsasg <735273025@qq.com> Date: Thu, 2 Jan 2025 16:22:58 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BF=AE=E6=94=B9=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E6=8E=A5=E5=8F=A3=E5=8F=8A=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.local | 3 +++ app/admin/controller/v1/Captcha.php | 21 +++++++++++---- app/admin/controller/v1/Login.php | 27 +++++++++++++++++-- app/admin/validate/v1/LoginValidate.php | 4 +++ app/common.php | 36 +++++++++++++++++++++++++ composer.json | 4 ++- config/captcha.php | 2 +- config/jwt.php | 21 +++++++++++++++ 8 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 config/jwt.php diff --git a/.env.local b/.env.local index 8abefefd..042786a0 100644 --- a/.env.local +++ b/.env.local @@ -10,3 +10,6 @@ DB_CHARSET = utf8mb4 DB_PREFIX = ow_ DEFAULT_LANG = zh-cn + +[JWT] +SECRET=b43e6276644ed60e65c50d1b324ba10b diff --git a/app/admin/controller/v1/Captcha.php b/app/admin/controller/v1/Captcha.php index 836d088a..91edd478 100644 --- a/app/admin/controller/v1/Captcha.php +++ b/app/admin/controller/v1/Captcha.php @@ -3,6 +3,7 @@ declare (strict_types = 0); namespace app\admin\controller\v1; +use think\facade\Cache; use think\facade\Config; class Captcha @@ -10,12 +11,22 @@ class Captcha /** * 获取验证码 */ - public function index(\think\Config $config, \think\Session $session) + public function index() { + // 生成token + $token = md5(uniqid() . random_str(8, 'all')); + + // 生成验证码 + $captcha = \think\captcha\facade\Captcha::create(); + + // 缓存验证码 + $hash = password_hash($captcha['code'], PASSWORD_BCRYPT, ['cost' => 10]); + Cache::store('redis')->set('captcha:token.' . $token, $hash, Config::get('captcha.expire')); + // 输出验证码 - $captcha = new \think\captcha\Captcha($config, $session); - $data = $captcha->create(); - - return success('获取验证码成功!', $data["img"]); + return success('获取验证码成功!', [ + 'token' => $token, + 'captcha' => $captcha["img"], + ]); } } diff --git a/app/admin/controller/v1/Login.php b/app/admin/controller/v1/Login.php index 5216d22b..f3bb1710 100644 --- a/app/admin/controller/v1/Login.php +++ b/app/admin/controller/v1/Login.php @@ -5,6 +5,7 @@ namespace app\admin\controller\v1; use app\admin\model\v1\UserModel; use app\admin\validate\v1\LoginValidate; +use thans\jwt\facade\JWTAuth; use think\facade\Cache; class Login @@ -18,6 +19,8 @@ class Login $post = request()->post([ 'username', 'password', + 'token', + 'captcha' ]); // 验证参数 @@ -25,6 +28,18 @@ class Login if (!$validate->check($post)) { return error($validate->getError()); } + + // 校验验证码 + $code = Cache::get('captcha:token.' . $post['token']); + if (!$code) { + return error('验证码不存在或已过期!'); + } + Cache::delete('captcha:token.' . $post['token']); + + // 校验 + if (!password_verify($post['captcha'], $code)) { + return error('验证码错误!'); + } // 验证用户 $user = UserModel::usernameOrMobile($post['username'])->find(); @@ -41,7 +56,15 @@ class Login if ($user['status'] == -1) { return error('用户已禁用,请联系管理员!'); } - dump(session("ss")); - return $user; + + // 生成 jwt token + $token = JWTAuth::builder(['uid' => $user['id']]); + + return success('登录成功!', [ + 'uid' => $user['id'], + 'nickname' => $user['nickname'], + 'avatar' => $user['avatar'], + 'token' => $token, + ]); } } diff --git a/app/admin/validate/v1/LoginValidate.php b/app/admin/validate/v1/LoginValidate.php index 922c32c1..4bf1dd15 100644 --- a/app/admin/validate/v1/LoginValidate.php +++ b/app/admin/validate/v1/LoginValidate.php @@ -16,6 +16,8 @@ class LoginValidate extends Validate protected $rule = [ 'username' => 'require', 'password' => 'require', + 'token' => 'require', + 'captcha' => 'require' ]; /** @@ -27,5 +29,7 @@ class LoginValidate extends Validate protected $message = [ 'username.require' => '用户名不能为空', 'password.require' => '密码不能为空', + 'token.require' => '验证码token不能为空', + 'captcha.require' => '验证码不能为空' ]; } diff --git a/app/common.php b/app/common.php index 730cfc82..eaa9309d 100644 --- a/app/common.php +++ b/app/common.php @@ -32,4 +32,40 @@ if (!function_exists('password_with_salt')) { { return md5(hash('sha256', $password . $salt)); } +} + +// 生成随机字符串 +if (!function_exists('random_str')) { + /** + * 生成随机字符串 + * @param $length integer 生成的长度 + * @param $type string 要生成的字符串类型(number, string, all) + * @param $convert integer 大小写转换0为小写1为大写 + * @return string + */ + function random_str($length, $type = "string", $convert = "0") + { + $conf = [ + 'number' => '0123456789', + 'string' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=' + ]; + $string = $conf[$type]; + if (!$string) { + $string = $conf['string']; + } + $strlen = strlen($string) - 1; + $char = ''; + for ($i = 0; $i < $length; $i++) { + $char .= $string[mt_rand(0, $strlen)]; + } + if ($convert > 0) { + $res = strtoupper($char); + } elseif ($convert == 0) { + $res = $char; + } elseif ($convert < 0) { + $res = strtolower($char); + } + return $res; + } } \ No newline at end of file diff --git a/composer.json b/composer.json index 605d3e8a..1ef17911 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,9 @@ "topthink/think-multi-app": "^1.1", "topthink/think-migration": "^3.1", "topthink/think-view": "^2.0", - "topthink/think-captcha": "^3.0" + "topthink/think-captcha": "^3.0", + "thans/tp-jwt-auth": "^2.2", + "topthink/think-throttle": "*" }, "require-dev": { "symfony/var-dumper": ">=4.2", diff --git a/config/captcha.php b/config/captcha.php index bff13d48..e1f41ee2 100644 --- a/config/captcha.php +++ b/config/captcha.php @@ -9,7 +9,7 @@ return [ // 验证码字符集合 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', // 验证码过期时间 - 'expire' => 1800, + 'expire' => 300, // 是否使用中文验证码 'useZh' => false, // 是否使用算术验证码 diff --git a/config/jwt.php b/config/jwt.php new file mode 100644 index 00000000..fd94fc3a --- /dev/null +++ b/config/jwt.php @@ -0,0 +1,21 @@ + env('JWT_SECRET'), + //Asymmetric key + 'public_key' => env('JWT_PUBLIC_KEY'), + 'private_key' => env('JWT_PRIVATE_KEY'), + 'password' => env('JWT_PASSWORD'), + //JWT time to live + 'ttl' => env('JWT_TTL', 60), + //Refresh time to live + 'refresh_ttl' => env('JWT_REFRESH_TTL', 20160), + //JWT hashing algorithm + 'algo' => env('JWT_ALGO', 'HS256'), + //token获取方式,数组靠前值优先 + 'token_mode' => ['header', 'cookie', 'param'], + //黑名单后有效期 + 'blacklist_grace_period' => env('BLACKLIST_GRACE_PERIOD', 10), + 'blacklist_storage' => thans\jwt\provider\storage\Tp6::class, +];