在现在前后端分离的时代,使用PHP开发APP后台API(接口)是很多公司的选择。但是传统的PHP开发API没有系统的把PHP当做一个工程化的项目来开发,没有明确各个模块的职责,所以本文写的是一种比较通用的PHP开发API的方式,简单的从API输入输出、API鉴权,业务异常处理等模块来描述API各个模块以及各个模块之间的关系。
本文采用laravel8+redis+mysql实现一个简单的登录功能,以及获取用户数据。
一、下载jwt扩展库:使用composer下载
composer require lcobucci/jwt
接着执行,生成自动加载文件
composer dump-autoload
可以参考这篇文章:Laravel8安装jwt扩展
二、创建数据库和数据表
创建用户表
/* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 50726 Source Host : localhost:3306 Source Schema : laravel8 Target Server Type : MySQL Target Server Version : 50726 File Encoding : 65001 Date: 15/10/2020 14:17:27 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for l_user -- ---------------------------- DROP TABLE IF EXISTS `l_user`; CREATE TABLE `l_user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL, `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL, `created_at` timestamp(0) NULL DEFAULT NULL, `updated_at` timestamp(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `email`(`email`) USING BTREE ) ENGINE = MyISAM AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of l_user -- ---------------------------- INSERT INTO `l_user` VALUES (1, 'admin', '123456@qq.com', '$2y$10$SojwOG45s8BaDi00NnDvnO4U.Y.BUPsDEwJc5AILAyRrNwoI5b3Wy', NULL, NULL); SET FOREIGN_KEY_CHECKS = 1;
说明:默认账号123456@qq.com 密码:123456
三、创建文件和编写代码
1、 添加路由web.php
<?php use Illuminate\Support\Facades\Route; Route::get('/info', [App\Http\Controllers\Admin\LoginController::class, 'info'])->name('admin.login.info')->middleware('CheckLogin'); //获取用户信息接口 Route::get('/login', [App\Http\Controllers\Admin\LoginController::class, 'login'])->name('admin.login.login'); //登录接口 ?>
2、封装jwt:项目根目录下新建Common\Auth\JwtAuth.php
<?php namespace App\Http\Common\Auth; /* * 单例 一次请求中所有出现使用jwt的地方都是一个用户 * class JwtAuth * * */ use Lcobucci\JWT\Builder; use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\ValidationData; class JwtAuth { /* * jwt token * */ private $token; /* * claim iss * @var string * */ private $iss = 'api.test.com'; /* * claim aud * @var string * */ private $aud = 'server_app'; /* * claim uid * @var * */ private $uid; /* * claim uid * @var * */ /* * claim secrect * @var string * */ private $secrect = '@#dslaci%hsbcbbc*hh'; /* * decode token * @var * */ private $decodeToken; /* * 单例模式 jwtAuth句柄 * @var * */ private static $instance; /* * 获取jwtAuth的句柄 * @return JwtAuth * */ public static function getInstace(){ if(is_null(self::$instance)){ self::$instance = new self(); } return self::$instance; } /* * 私有化构造函数 * JwtAuth constructor. * */ private function __construct() { } /* * 私有化克隆函数 * */ private function __clone(){ } /* * 获取token * @return string * */ public function getToken(){ return (string)$this->token; } /* * 设置token * @param $token * @return $this * */ public function setToken($token){ $this->token = $token; } /* *uid * @parm $uid * */ public function setUid($uid) { $this->uid = $uid; return $this; } public function getUid() { return $this->uid; } /* * 编码jwt token * @return $this * */ public function encode() { $time = time(); $this->token = (new Builder())->setHeader('alg','HS256') ->setIssuer('api.test.com') ->setAudience($this->aud) ->setIssuedAt($time) ->setExpiration($time + 3600) ->set('uid', $this->uid) ->sign(new Sha256(),$this->secrect) ->getToken(); return $this; } /* * parse string token * @return \Lcobucci\JWT\Token * */ public function decode() { if(!$this->decodeToken){ $this->decodeToken = (new Parser())->parse((string)$this->token); $this->uid = $this->decodeToken->getClaim('uid'); } return $this->decodeToken; } /* * verify token * 验证token有没被篡改 * */ public function verify() { $result = $this->decode()->verify(new Sha256(),$this->secrect); return $result; } /* * validate * @return bool * */ public function validate() { $data = new ValidationData(); $data->setIssuer($this->iss); $data->setAudience($this->aud); return $this->decode()->validate($data); } } ?>
3、 创建中间件:app\Http\Middleware\CheckLogin.php
<?php namespace App\Http\Middleware; use App\Http\Common\Auth\JwtAuth; use Closure; use Illuminate\Http\Request; class CheckLogin { use ResponseJson; /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle(Request $request, Closure $next) { $token = $request->input('token'); if ($token) { $jwtAuth = JwtAuth::getInstace(); $jwtAuth->setToken($token); if ($jwtAuth->validate() && $jwtAuth->verify()) { return $next($request); } else { return response()->json(['code'=>500,'msg'=>'登录过期']); } } else { return response()->json(['code'=>500,'msg'=>'参数错误']); } } } ?>
4、 登录接口和获取数据接口,使用redis缓存加速用户信息接口获取数据。
<?php namespace App\Http\Controllers\Admin; use App\Http\Common\Auth\JwtAuth; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Redis; class LoginController extends Controller { /* * 用户登录 * * @param Request $request * @return false|string * */ public function login(Request $request){ //获取客户端传递的参数 $email = $request->input('email'); $password = $request->input('password'); //去数据库中查询改用户信息 $res=DB::table('user')->where('email',$email)->first(); if(!$res){ return response()->json(['code'=>500,'msg'=>'用户不存在']); } //password_hash() $userPasswordHash = $res->password; if(!password_verify($password,$userPasswordHash)){ return response()->json(['code'=>500,'msg'=>'用户密码错误']); } $jwtAuth = JwtAuth::getInstace(); $token = $jwtAuth->setUid($res->id)->encode()->getToken(); return response()->json([ 'code'=>200,'msg'=>'登录成功', 'token'=>$token ]); } /* * 用户信息获取 * * @return false|string * */ public function info(){ $jwtAuth = JwtAuth::getInstace(); $uid = $jwtAuth->getUid(); $cacheUserInfo = Redis::get('uid:'. $uid); // dd($cacheUserInfo); if(!$cacheUserInfo){ $user = DB::table('user')->where('id',$uid)->first(); if(!$user){ return response()->json([ 'code'=>500,'msg'=>'用户密码错误' ]); } Redis::setex('uid:'.$uid,3600,json_encode($user) ); }else{ $user = json_decode($cacheUserInfo); } return response()->json([ 'code'=>500, 'msg'=>'获取成功', 'name'=>$user->name, 'email'=>$user->email ]); } } ?>
四、测试接口数据[使用postman来测试接口数据]
1、访问登录接口:携带email和password
http://www.laravel8.com/login?email=123456@qq.com&password=123456
2、访问获取数据接口:携带上面生成的token,返回用户信息
http://www.laravel8.com/info?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhcGkudGVzdC5jb20iLCJhdWQiOiJzZXJ2ZXJfYXBwIiwiaWF0IjoxNjAyNzQxMDYyLCJleHAiOjE2MDI3NDQ2NjIsInVpZCI6MX0.UdQP30IhNuhe-1jd_iYXHIl6-23EwNisea4oSe_0z7c
以上是一个简单的使用jwt实现登录登录功能,供大家参看。
文章评论(0)