diff --git a/app/BaseController.php b/app/BaseController.php index 085680e..c352ffe 100644 --- a/app/BaseController.php +++ b/app/BaseController.php @@ -36,6 +36,10 @@ abstract class BaseController */ protected $middleware = []; + const JSON_SUCCESS_STATUS = 200; + + const JSON_ERROR_STATUS = 201; + /** * 构造方法 * @access public @@ -91,4 +95,37 @@ abstract class BaseController return $v->failException(true)->check($data); } + /** + * 返回操作成功json + * @param array $data + * @param string $msg + * @return array + */ + protected function renderSuccess($msg = 'success', $data = []) + { + return $this->renderJson(self::JSON_SUCCESS_STATUS, $msg, $data); + } + + /** + * 返回操作失败json + * @param string $msg + * @param array $data + * @return array + */ + protected function renderError($msg = 'error', $data = []) + { + return $this->renderJson(self::JSON_ERROR_STATUS, $msg, $data); + } + + /** + * 返回封装后的 API 数据到客户端 + * @param int $code + * @param string $msg + * @param array $data + * @return array + */ + protected function renderJson($code = self::JSON_SUCCESS_STATUS, $msg = '', $data = []) + { + return json(['code' => $code, 'msg' => $msg,'data' => $data]); + } } diff --git a/app/common.php b/app/common.php index 57cb6d8..80fe7d0 100644 --- a/app/common.php +++ b/app/common.php @@ -1,2 +1,60 @@ $key, //签发者 可以为空 + "aud" => '', //面象的用户,可以为空 + "iat" => time(), //签发时间 + "nbf" => time() + 3, //在什么时候jwt开始生效 (这里表示生成100秒后才生效) + "exp" => time() + 7200, //token 过期时间 + "data" => $data //记录的userid的信息,这里是自已添加上去的,如果有其它信息,可以再添加数组的键值对 + ); + return JWT::encode($token, $key, "HS384"); //根据参数生成了token,可选:HS256、HS384、HS512、RS256、ES256等 +} + +/** + * 验证token + * @param $token + * @return array|int[] + * @author whj + * @date 2023-08-22 15:31 + */ +function checkToken($token): array +{ + $key = 'LAL@lc!'; + $status = array("code" => 2); + try { + JWT::$leeway = 60; //当前时间减去60,把时间留点余地 + $decoded = JWT::decode($token, new Key($key, 'HS384')); //同上的方式,这里要和签发的时候对应 + $arr = (array)$decoded; + $res['code'] = 200; + $res['data'] = $arr['data']; + $res['data'] = json_decode(json_encode($res['data']), true);//将stdObj类型转换为array + return $res; + + } catch (\Firebase\JWT\SignatureInvalidException $e) { //签名不正确 + $status['msg'] = "签名不正确"; + return $status; + } catch (\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用 + $status['msg'] = "token失效"; + return $status; + } catch (\Firebase\JWT\ExpiredException $e) { // token过期 + $status['msg'] = "token失效"; + return $status; + } catch (Exception $e) { //其他错误 + $status['msg'] = "未知错误"; + return $status; + } +} \ No newline at end of file diff --git a/app/controller/User.php b/app/controller/User.php index 2bff4d2..b483fd3 100644 --- a/app/controller/User.php +++ b/app/controller/User.php @@ -2,11 +2,126 @@ namespace app\controller; use app\BaseController; +use app\model\User as UserModel; +use app\validate\User as UserValidate; +use think\exception\ValidateException; +use think\facade\Request; class User extends BaseController { - public function hello($name = 'ThinkPHP6') + /** + * 用户注册 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author whj + * @date 2023-08-22 17:04 + */ + public function register() { - return 'hello,' . $name; + $data = Request::param(); + + try { + // 验证用户输入 + validate(UserValidate::class)->scene('register')->check($data); + + // 验证手机号短信验证码 + $userModel = new UserModel(); + $smsCode = $data['sms_code']; + $phone = $data['phone']; + + if (!isset($data['invite_code'])) $data['invite_code'] = ''; + $invite_code = $data['invite_code']; + + if (!empty($invite_code) && !$userModel->verifyInviteCode($invite_code)) { + return $this->renderError('邀请码无效'); + } + + if (!$userModel->verifySmsCode($phone, $smsCode)) { + return $this->renderError('短信验证码错误'); + } + + // 注册用户 + if ($userModel->register($data)) { + return $this->renderSuccess('注册成功'); + } else { + return $this->renderSuccess('手机号已注册'); + } + } catch (ValidateException $exception) { + return $this->renderError($exception->getMessage()); + } + } + + /** + * 用户登录 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author whj + * @date 2023-08-22 17:04 + */ + public function login() + { + $data = Request::param(); + + try { + // 验证用户输入 + validate(UserValidate::class)->scene('login')->check($data); + + // 用户登录 + $userModel = new UserModel(); + $user = $userModel->login($data); + + if ($user['status']) { + + $userinfo = ['id' => $user['data']['id'], 'username' => $user['data']['name']]; + $token = ['token'=>signToken($userinfo)]; + + return $this->renderSuccess('登陆成功',$token); + } else { + return $this->renderError($user['msg']); + } + } catch (ValidateException $exception) { + return $this->renderError($exception->getMessage()); + } + } + + /** + * 找回密码 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author whj + * @date 2023-08-22 17:22 + */ + public function retrieve() + { + $data = Request::param(); + + try { + // 验证用户输入 + validate(UserValidate::class)->scene('retrieve')->check($data); + + $userModel = new UserModel(); + $phone = $data['phone']; + $smsCode = $data['sms_code']; + + if (!$userModel->verifySmsCode($phone, $smsCode)) { + return $this->renderError('短信验证码错误'); + } + + $user = $userModel->retrieve($data); + + if ($user['status']) { + return $this->renderSuccess('密码重置成功'); + } else { + return $this->renderError($user['msg']); + } + } catch (ValidateException $exception) { + return $this->renderError($exception->getMessage()); + } } } \ No newline at end of file diff --git a/app/middleware/CheckToken.php b/app/middleware/CheckToken.php new file mode 100644 index 0000000..c9600c7 --- /dev/null +++ b/app/middleware/CheckToken.php @@ -0,0 +1,36 @@ +userInfo = $userinfo['data']; + } + catch (\Exception $err){ + return json(['code'=>$err->getCode(),'msg'=>$err->getMessage()]); + } + return $next($request); + } +} diff --git a/app/model/User.php b/app/model/User.php new file mode 100644 index 0000000..8c80864 --- /dev/null +++ b/app/model/User.php @@ -0,0 +1,178 @@ +where('phone', $data['phone'])->find(); + if ($user) return false; + + // 生成盐值 + $salt = $this->generateSalt(); + // 密码加盐值后哈希存储 + $password = $this->generateHashedPassword($data['password'], $salt); + + $this->save([ + 'username' => $this->generateRandomUsername(), + 'password' => $password, + 'salt' => $salt, + 'phone' => $data['phone'], + 'invite_code' => $data['invite_code'], + 'register_time' => date("Y-m-d H:i:s",time()) + ]); + + return true; + } + + /** + * 用户登录 + * @param $data + * @return User|array|mixed|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author whj + * @date 2023-08-22 16:28 + */ + public function login($data) + { + // 根据用户名查询用户信息 + $user = $this->where('phone', $data['phone'])->find(); + + if ($user) { + // 使用相同的盐值对输入密码进行哈希验证 + $hashedPassword = $this->generateHashedPassword($data['password'], $user->salt); + + if ($user->password === $hashedPassword) { + // 登录成功 + return ['status' => true, 'msg' => '手机号未注册', 'data' => $user]; + } else { + + return ['status' => false, 'msg' => '密码错误']; + } + } + + return ['status' => false, 'msg' => '手机号未注册']; + } + + /** + * 找回密码 + * @param $data + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function retrieve($data) + { + // 根据用户名查询用户信息 + $user = $this->where('phone', $data['phone'])->find(); + + if ($user) { + + // 生成盐值 + $salt = $this->generateSalt(); + // 密码加盐值后哈希存储 + $user->password = $this->generateHashedPassword($data['password'], $salt); + $user->salt = $salt; + $user->update_time = date("Y-m-d H:i:s",time()); + $this->save(); + + return ['status' => true, 'msg' => '密码重制成功']; + } + + return ['status' => false, 'msg' => '手机号未注册']; + } + + /** + * 手机号短信验证码验证 + * @param $phone + * @param $smsCode + * @return bool + */ + public function verifySmsCode($phone, $smsCode) + { + // 在这个方法中,您可以调用您的短信服务提供商的API进行验证码验证 + // 这里简化为直接比较验证码 + // 请根据实际情况自行实现验证码验证逻辑 + + // 假设存储了正确的短信验证码 + $correctSmsCode = '123456'; + + if ($smsCode === $correctSmsCode) { + return true; + } + + return false; + } + + /** + * 验证邀请码是否有效 + * @param $invite_code + * @return bool + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function verifyInviteCode($invite_code) + { + $codeRes = $this->where('invite_code',$invite_code)->find(); + + if (empty($codeRes)) { + return false; + } + + return true; + } + + /** + * 生成盐值 + * @return string + */ + private function generateSalt() + { + return $this->generateRandomUsername(6); + } + + /** + * 密码加盐值后哈希存储 + * @param $password + * @param $salt + * @return string + */ + private function generateHashedPassword($password, $salt) + { + return md5(md5($password) . md5($salt)); + } + + /** + * 获取随机用户命 + * @param $length + * @return string + */ + private function generateRandomUsername($length = 8) { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $username = ''; + + $maxIndex = strlen($characters) - 1; + for ($i = 0; $i < $length; $i++) { + $randomIndex = mt_rand(0, $maxIndex); + $username .= $characters[$randomIndex]; + } + + return $username; + } +} \ No newline at end of file diff --git a/app/validate/User.php b/app/validate/User.php new file mode 100644 index 0000000..3f84070 --- /dev/null +++ b/app/validate/User.php @@ -0,0 +1,42 @@ + ['规则1','规则2'...] + * + * @var array + */ + protected $rule = [ + 'phone' => 'require|mobile', + 'password' => 'require|min:6|max:20', + 'sms_code' => 'require', + ]; + + /** + * 定义错误信息 + * 格式:'字段名.规则名' => '错误信息' + * + * @var array + */ + protected $message = [ + 'phone.require' => '手机号必填', + 'phone.mobile' => '手机号不正确', + 'password.require' => '密码必填', + 'password.min' => '密码长度最短为6个字符', + 'password.max' => '密码长度最长为20个字符', + 'sms_code' => '短信验证码必填' + ]; + + protected $scene = [ + 'login' => ['phone','password'], + 'register' => ['phone','password','sms_code'], + 'retrieve' => ['phone','password','sms_code'] + ]; +} diff --git a/config/database.php b/config/database.php index ba2ae8c..e72ea8c 100644 --- a/config/database.php +++ b/config/database.php @@ -26,11 +26,11 @@ return [ // 服务器地址 'hostname' => env('database.hostname', '127.0.0.1'), // 数据库名 - 'database' => env('database.database', ''), + 'database' => env('database.database', 'guaguale'), // 用户名 'username' => env('database.username', 'root'), // 密码 - 'password' => env('database.password', ''), + 'password' => env('database.password', 'root'), // 端口 'hostport' => env('database.hostport', '3306'), // 数据库连接参数 @@ -38,7 +38,7 @@ return [ // 数据库编码默认采用utf8 'charset' => env('database.charset', 'utf8'), // 数据库表前缀 - 'prefix' => env('database.prefix', ''), + 'prefix' => env('database.prefix', 'ggl_'), // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, diff --git a/route/app.php b/route/app.php index d8e09e3..5484327 100644 --- a/route/app.php +++ b/route/app.php @@ -14,4 +14,11 @@ Route::get('think', function () { return 'hello,ThinkPHP6!'; }); -Route::get('hello/:name', 'index/hello'); + +Route::group('user',function (){ + Route::post('register','user/register'); + Route::post('login','user/login'); + Route::post('retrieve','user/retrieve'); +}); + +