用户登录核心代码
用户登录的核心思路与传统的登录基本相同,不同的地方就是web开发中
使用session或者cookies来进行授权验证,在接口开发中,由于接口的大部分使用场景是跨域的,所以一般采用令牌来实现授权限证。
实现思路
当用户登录成功后,在服务器端生成令牌token
并在服务器端存储,然后下发到客户端,当用户访问需要授权的接口时,需要携带该令牌,然后在务器端完成验证。
在这里令牌需要具体一下特点:
- 由服务器端生成并存储
- 惟一性
- 具有生命周期
//用户登录 Route::post("/:ver/login", ":ver.Login/login");
创建
app\api\constroller\v1\Login.php
控制器php think make:controller api@v1/Login
登录方法
public function login(Request $request){ //1. 数据验证 (new LoginValidate())->runCheck(); //2.登录验证,到数据库中查询用户信息 ,并生成令牌 $data = $request->post(); (new User())->checkLogin($data); //4.响应 $datas = [ 'username'=>$data['username'], 'token'=>$token ]; return $this->return_msg('ok',$datas,0,200);
创建验证器
app\api\validate\Login.php
namespace app\api\validate;
use app\api\libs\Sendsms;
class Login extends BaseValidate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
'username'=>"username|require|mobile",
'password'=>"password|require|min:6",
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'username.require'=>"用户名不能为空",
'username.mobile'=>"用户名必须是手机号",
'password.require'=>"密码不能为空",
'password.min'=>"密码长度不能小于6位",
];
}
user
模型中checkLogin
方法
//用户登录
publicstaticfunctioncheckLogin($data){
//1.查询用户信息,根据用户名查询
$user\=self::where('username','=',$data\['username'\])\->field(\['id,username,password'\])\->find();
if(!$user){
thrownewHttpExceptions(403,"账号不存在",10000);
}
//验证密码是否正确
if(password\_verify($data\['password'\],$user\['password'\])){
returntrue;
}
thrownewHttpExceptions(403,"密码不正确",10001);
}
令牌授权时,需要生成令牌和令牌验证,为了方便后期的扩展,在这里直接编写成一个独立的类库来实现这一功能。
在app\api\libs\
下创建类文件Auth.php
<?php
namespace app\api\libs;
use app\api\model\User;
use app\exception\HttpExceptions;
use think\facade\Request;
/**
* 1.生成令牌
* 2.设置登录状态
* 3.验证登录状态
* Class Auth
* @package app\api\libs
*/
class Auth
{
private $token = '';
private $username = '';
private static $instance = null;
private function __construct()
{
$request = Request::instance();
$this->username = $request->post('username');
$this->token = $request->param('token');
}
private function __clone()
{
// TODO: Implement __clone() method.
}
//统一的入口
public static function getInstance(){
if(!self::$instance instanceof self){
self::$instance = new self();
}
return self::$instance;
}
//获取token
public function getToken(){
return $this->token;
}
//生成token
private function createToken(){
$this->token = md5($this->username.time().rand(100000,999999));
}
//设置token 保持登录状态
public function setToken(){
$this->createToken();
//写入数据表
$user = (new User())->where('username','=',$this->username)->find();
$user->login_code = $this->token;
$user->expiration_time = time()+config('auth.expire_time');
$user->save();
return $this;
}
//验证,10006:无权限
public function checkLogin(){
//1.到数据库中查询用户信息,token
$user = (new User())->where('login_code','=',$this->token)->find();
if(!$user){
throw new HttpExceptions(403,"无权限",10006);
}
//2. 登录是否过期 10007:超时
if($user['expiration_time']<time()){
throw new HttpExceptions(403,"登录超时",10007);
}
//延期过期时间
if(($user->expiration_time-time())<5){
$user->expiration_time = time()+config('auth.expire_time');
$user->save();
}
// echo $user->expiration_time."\n";
return true;
}
}
用户的登录授权验证这一块,为了后期扩展的方便,所以在这里咱们将其放到中间件中处理。然后在路由中调用中间件进行验证。
创建中间件app\middleware\CheckApiLogin.php
<?php
namespace app\middleware;
use app\api\libs\Auth;
class CheckApiLogin
{
public function handle($request, \Closure $next)
{
// 令牌验证
Auth::getInstance()->checkLogin();
return $next($request);
}
}
设置中间件别名,需要在配置文件中设置,在对应应用配置目录下新建middleware.php
配置文件
<?php
return [
'alias' => [
'check' => \app\middleware\CheckApiLogin::class
],
];
在需要授权验证的路由上添加上验证中间件即可。
Route::post('/:ver/test1',":ver.Login/test1")\->middleware('check');
Route::post('/:ver/test',":ver.Login/test")->middleware('check');