Browse Source

jwt部署,登陆、注册、找回密码接口

master
wanghongjun 3 years ago
parent
commit
b7f08c036a
  1. 37
      app/BaseController.php
  2. 58
      app/common.php
  3. 119
      app/controller/User.php
  4. 36
      app/middleware/CheckToken.php
  5. 178
      app/model/User.php
  6. 42
      app/validate/User.php
  7. 6
      config/database.php
  8. 9
      route/app.php

37
app/BaseController.php

@ -36,6 +36,10 @@ abstract class BaseController
*/ */
protected $middleware = []; protected $middleware = [];
const JSON_SUCCESS_STATUS = 200;
const JSON_ERROR_STATUS = 201;
/** /**
* 构造方法 * 构造方法
* @access public * @access public
@ -91,4 +95,37 @@ abstract class BaseController
return $v->failException(true)->check($data); 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]);
}
} }

58
app/common.php

@ -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;
}
}

119
app/controller/User.php

@ -2,11 +2,126 @@
namespace app\controller; namespace app\controller;
use app\BaseController; 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 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());
}
} }
} }

36
app/middleware/CheckToken.php

@ -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);
}
}

178
app/model/User.php

@ -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;
}
}

42
app/validate/User.php

@ -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']
];
}

6
config/database.php

@ -26,11 +26,11 @@ return [
// 服务器地址 // 服务器地址
'hostname' => env('database.hostname', '127.0.0.1'), 'hostname' => env('database.hostname', '127.0.0.1'),
// 数据库名 // 数据库名
'database' => env('database.database', ''), 'database' => env('database.database', 'guaguale'),
// 用户名 // 用户名
'username' => env('database.username', 'root'), 'username' => env('database.username', 'root'),
// 密码 // 密码
'password' => env('database.password', ''), 'password' => env('database.password', 'root'),
// 端口 // 端口
'hostport' => env('database.hostport', '3306'), 'hostport' => env('database.hostport', '3306'),
// 数据库连接参数 // 数据库连接参数
@ -38,7 +38,7 @@ return [
// 数据库编码默认采用utf8 // 数据库编码默认采用utf8
'charset' => env('database.charset', 'utf8'), 'charset' => env('database.charset', 'utf8'),
// 数据库表前缀 // 数据库表前缀
'prefix' => env('database.prefix', ''), 'prefix' => env('database.prefix', 'ggl_'),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0, 'deploy' => 0,

9
route/app.php

@ -14,4 +14,11 @@ Route::get('think', function () {
return 'hello,ThinkPHP6!'; 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');
});

Loading…
Cancel
Save