简介:在前后端分离的时代,使用PHP开发APP后台API(接口)是很多公司的选择。但是传统的PHP开发API没有系统的把PHP当做一个工程化的项目来开发,没有明确各个模块的职责,所以本期相对的提出了一种比较通用的PHP开发API的方式,简单的从API输入输出、API鉴权,业务异常处理等模块来描述API各个模块以及各个模块之间的关系。在最后,介绍了一个API实例,该实例串联了API的各个模块,让大家达到融汇贯通的效果。
环境:lnmp (采用laradock搭建)
框架:laravel6.*
参考:https://github.com/lcobucci/jwt/blob/3.3/README.md首先什么是JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
下面进入代码实战环节:
composer require lcobucci/jwt
<?php namespace App\Common\Auth;use Lcobucci\JWT\Builder;use Lcobucci\JWT\Parser;use Lcobucci\JWT\Signer\Hmac\Sha256;use Lcobucci\JWT\Signer\Key;use Lcobucci\JWT\ValidationData;class JwtAuth{/**
* @var
*/private $token;private $decodeToken;private $iss = 'laravel_base.test';private $aud = 'laravel_base_service';private $uid;private $secrect = 'asfshgeatg';private $signer = 'strines';private static $instance = null;//构造器私有化:禁止从类外部实例化private function __construct(){}//克隆方法私有化:禁止从外部克隆对象private function __clone(){}//因为用静态属性返回类实例,而只能在静态方法使用静态属性//所以必须创建一个静态方法来生成当前类的唯一实例public static function getInstance(){//检测当前类属性$instance是否已经保存了当前类的实例if (self::$instance == null) {//如果没有,则创建当前类的实例self::$instance = new self();
}//如果已经有了当前类实例,就直接返回,不要重复创建类实例return self::$instance;
}/**
* @return string
*/public function getToken(){return (string)$this->token;
}/**
* @param $token
* @return $this
*/public function setToken($token){$this->token = $token;return $this;
}public function getUid(){return $this->uid;
}/**
* @param $uid
* @return $this
*/public function setUid($uid){$this->uid = $uid;return $this;
}/**
* @return $this
*/public function encode(){
$time = time();
$signer = new Sha256();$this->token = (new Builder())->issuedBy($this->iss) // Configures the issuer (iss claim)
->permittedFor($this->aud) // Configures the audience (aud claim)
->identifiedBy($this->secrect, true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', $this->uid) // Configures a new claim, called "uid"
->getToken($signer, new Key($this->signer)); // Retrieves the generated tokenreturn $this;
}/**
* @return \Lcobucci\JWT\Token
*/public function decode(){if (!$this->decodeToken)
{$this->decodeToken = (new Parser())->parse((string) $this->token); // Parses from a string$this->uid = $this->decodeToken->getClaim('uid');
}return $this->decodeToken;
}/**
* @return bool
*/public function verify(){
$signer = new Sha256();
$result = $this->decode()->verify($signer, $this->signer);return $result;
}/**
* @return bool
*/public function validate(){
$data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer($this->iss);
$data->setAudience($this->aud);
$data->setId($this->secrect);return $this->decode()->validate($data);
}
}
接下来就可以在控制器中使用了,如:
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(){
$jwtAuth = JwtAuth::getInstance();
$token = $jwtAuth->setUid(2)->encode()->getToken();
return $this->jsonSuccessResponse([
'token' => $token
]);
}
访问接口每次都要携带token令牌,那么怎么验证呢?那就是laravel路由中间件,如:
中间件是这样实现的,如:
<?php namespace App\Http\Middleware;use App\Common\Auth\JwtAuth;use App\Common\Err\ApiErrDesc;use App\Exceptions\ApiException;use App\Http\Response\JsonResponse;use Closure;class JwtMiddleware{use JsonResponse;/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/public function handle($request, Closure $next){
$token = $request->header('token');if ($token)
{
$JwtAuth = JwtAuth::getInstance();
$JwtAuth->setToken($token);if ($JwtAuth->validate() && $JwtAuth->verify())
{return $next($request);
}else
{throw new ApiException(ApiErrDesc::ERR_TOKEN);
}
}else
{throw new ApiException(ApiErrDesc::ERR_MISSTOKEN);
}
}
}
路由是这样使用的,如:
Route::get('/login', 'Api\ApiController@index');
Route::middleware('jwt_auth')->namespace('Api')->group(function(){
Route::get('show','ApiController@show')->name('api.login');
});
有问题可以随时加作者微信交流