8 changed files with 479 additions and 6 deletions
@ -1,2 +1,60 @@ |
|||||
<?php |
<?php |
||||
// 应用公共文件 |
// 应用公共文件 |
||||
|
use \Firebase\JWT\JWT; |
||||
|
use Firebase\JWT\Key; |
||||
|
|
||||
|
/** |
||||
|
* 生成验签 |
||||
|
* @param $data |
||||
|
* @return string |
||||
|
* @author whj |
||||
|
* @date 2023-08-22 15:31 |
||||
|
*/ |
||||
|
function signToken($data): string |
||||
|
{ |
||||
|
$key = 'LAL@lc!'; //这里是自定义的一个随机字串,应该写在config文件中的,解密时也会用,相当于加密中常用的 盐-salt |
||||
|
$token = array( |
||||
|
"iss" => $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; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
<?php |
||||
|
declare (strict_types = 1); |
||||
|
|
||||
|
namespace app\middleware; |
||||
|
|
||||
|
use think\Exception; |
||||
|
use \think\facade\Request; |
||||
|
|
||||
|
class CheckToken |
||||
|
{ |
||||
|
/** |
||||
|
* |
||||
|
* 处理请求 |
||||
|
* @param $request |
||||
|
* @param \Closure $next |
||||
|
* @return mixed|\think\response\Json |
||||
|
* @author whj |
||||
|
* @date 2023-08-22 14:57 |
||||
|
*/ |
||||
|
public function handle($request, \Closure $next) |
||||
|
{ |
||||
|
try { |
||||
|
$token = Request::header()['token']??false; |
||||
|
if(!$token) |
||||
|
throw new Exception('Without Token',201); |
||||
|
$userinfo = checkToken($token); |
||||
|
if($userinfo['code'] != 200) |
||||
|
throw new Exception('Token checked error',202); |
||||
|
$request->userInfo = $userinfo['data']; |
||||
|
} |
||||
|
catch (\Exception $err){ |
||||
|
return json(['code'=>$err->getCode(),'msg'=>$err->getMessage()]); |
||||
|
} |
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,178 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\model; |
||||
|
|
||||
|
use think\Model; |
||||
|
|
||||
|
class User extends Model |
||||
|
{ |
||||
|
/** |
||||
|
* 注册用户 |
||||
|
* @param $data |
||||
|
* @return bool |
||||
|
* @throws \think\db\exception\DataNotFoundException |
||||
|
* @throws \think\db\exception\DbException |
||||
|
* @throws \think\db\exception\ModelNotFoundException |
||||
|
*/ |
||||
|
public function register($data) |
||||
|
{ |
||||
|
|
||||
|
$user = $this->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; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
<?php |
||||
|
declare (strict_types = 1); |
||||
|
|
||||
|
namespace app\validate; |
||||
|
|
||||
|
use think\Validate; |
||||
|
|
||||
|
class User extends Validate |
||||
|
{ |
||||
|
/** |
||||
|
* 定义验证规则 |
||||
|
* 格式:'字段名' => ['规则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'] |
||||
|
]; |
||||
|
} |
||||
Loading…
Reference in new issue