Skip to content

Commit 53554b0

Browse files
committed
v1.0
0 parents  commit 53554b0

12 files changed

+1187
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/vendor
2+
/.idea
3+
/.vscode
4+
/.vagrant
5+
.env

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 cyd622
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
![Laravel开发API助手](https://s2.ax1x.com/2019/03/27/Aajlgx.md.png)
2+
3+
4+
![Software license](https://img.shields.io/badge/license-MIT-green.svg)
5+
![Build](https://img.shields.io/badge/build-passing-0.svg)
6+
![dependencies](https://img.shields.io/badge/dependencies-up%20to%20date-brightgreen.svg)
7+
![stars](https://img.shields.io/badge/stars-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg)
8+
![php](https://img.shields.io/badge/php-%3E%3D%207.1-blueviolet.svg)
9+
![mysql](https://img.shields.io/badge/mysql-%3E%3D%205.5-informational.svg)
10+
![laravel](https://img.shields.io/badge/laravel-%3E%3D%205.5-red.svg)
11+
[![Latest Version](http://img.shields.io/packagist/v/cyd622/laravel-api.svg)](https://packagist.org/packages/cyd622/laravel-api)
12+
[![Monthly Downloads](https://img.shields.io/packagist/dm/cyd622/laravel-api.svg)](https://packagist.org/packages/cyd622/laravel-api)
13+
14+
15+
16+
# Laravel开发API助手
17+
*[将Laravel框架进行一些配置处理,让其在开发API时更得心应手]*
18+
19+
------
20+
21+
## 背景
22+
23+
随着前后端完全分离,`PHP`也基本告别了`view`模板嵌套开发,转而专门写资源接口。`Laravel`是PHP框架中`最优雅的框架`,国内也越来越多人告别`ThinkPHP`选择了`Laravel`。Laravel框架本身对`API`有支持,但是感觉再工作中还是需要再做一些处理。`Lumen`用起来不顺手,有些包不能很好地支持。所以,将Laravel框架进行一些配置处理,让其在开发API时更得心应手。
24+
25+
---
26+
27+
## 环境和程序要求
28+
29+
| 程序 | 版本 |
30+
| -------- | -------- |
31+
| PHP| `>= 7.1` |
32+
| MySQL| `>= 5.5` |
33+
| laravel/laravel| `>= 5.5` |
34+
| tymon/jwt-auth| `1.0.0-rc.4.*` |
35+
36+
37+
----
38+
39+
40+
## 功能
41+
42+
> - [x] 统一Response响应处理
43+
> - [x] Laravel Api-Resource资源 分页返回统一响应
44+
> - [x] jwt-auth用户认证与无感知自动刷新
45+
> - [x] jwt-auth多角色认证不串号
46+
> - [x] 单一设备登陆
47+
48+
-----
49+
50+
## 安装
51+
* 通过composer,这是推荐的方式,可以使用composer.json 声明依赖,或者直接运行下面的命令。
52+
53+
```shell
54+
composer require cyd622/laravel-api
55+
56+
```
57+
58+
* 放入composer.json文件中
59+
60+
```json
61+
"require": {
62+
"cyd622/laravel-api": "*"
63+
}
64+
```
65+
然后运行
66+
```shell
67+
composer update
68+
```
69+
70+
----
71+
72+
## 使用
73+
74+
添加服务提供商
75+
```
76+
'providers' => [
77+
...
78+
Cyd622\LaravelApi\ApiServiceProvider::class,
79+
]
80+
```
81+
2.发布配置文件
82+
```shell
83+
php artisan vendor:publish --provider="Cyd622\LaravelApi\ApiServiceProvider"
84+
```
85+
> 此命令会在 config 目录下生成一个 `laravel_api.php` 配置文件,你可以在此进行自定义配置。
86+
> * `response` 是配置资源响应格式
87+
> * `exception` 是配置需要拦截的异常
88+
89+
### 1.统一Response响应处理
90+
> 所有请求都返回`json`格式,返回字段格式也是统一标准化
91+
> 格式如下
92+
```
93+
{
94+
"message": "string",
95+
"code": xxx,
96+
"data": [] // 数组或对象
97+
}
98+
```
99+
> 默认`success`返回的`http`状态码是`200``error`返回的状态码是`400`
100+
101+
1. 新建Api控制器基类 或者 继承Api控制器基类
102+
2. `use ApiResponse;`
103+
3. 代码使用
104+
```php
105+
// 成功返回 第一个参数可接受item和resource
106+
return $this->success($user,$meta);
107+
// 只返回信息无内容
108+
return $this->setHttpCode(201)->setStatusCode(1002001)->message('用户创建成功...');
109+
// 错误返回
110+
return $this->error('用户登录失败',401,10001);
111+
```
112+
113+
114+
4.返回
115+
```
116+
// 成功完整返回
117+
{
118+
"message": "Success",
119+
"code": 200,
120+
"data": [
121+
{
122+
"id": 1,
123+
"name": "jack"
124+
},
125+
{
126+
"id": 2,
127+
"name": "tony"
128+
}
129+
],
130+
"meta": {
131+
"page_info": {
132+
"current_page": 1,
133+
"last_page": 20,
134+
"per_page": 15,
135+
"total": 500
136+
}
137+
}
138+
}
139+
140+
// 错误返回
141+
{
142+
"message": "Error",
143+
"code": 104041,
144+
"data": []
145+
}
146+
```
147+
148+
### 2.Api-Resource资源 分页返回统一响应
149+
1. 在Resource资源文件中引入
150+
2. `use PaginatedCollection;`
151+
示例代码
152+
```php
153+
namespace App\Http\Resources;
154+
155+
use App\Traits\PaginatedCollection;
156+
use Illuminate\Http\Resources\Json\JsonResource;
157+
158+
class Company extends JsonResource
159+
{
160+
use PaginatedCollection;
161+
162+
}
163+
```
164+
165+
3.使用示例
166+
```php
167+
return \App\Http\Resources\Company::collection($company);
168+
```
169+
4.返回同上成功返回示例
170+
171+
172+
> 关于分页返回的字段,你可以在配置文件中指定:`config('laravel_api.response.page_info')`
173+
默认是`current_page``last_page``per_page``total` 4个
174+
175+
### 3.异常自定义处理
176+
1.修改 `app/Exceptions` 目录下的 `Handler.php` 文件
177+
```php
178+
use LaravelApi\Response\ExceptionReport;
179+
180+
public function render($request, Exception $exception)
181+
{
182+
// 将方法拦截到自己的ExceptionReport
183+
$reporter = ExceptionReport::make($exception);
184+
185+
if ($reporter->shouldReturn()) {
186+
return $reporter->report();
187+
}
188+
189+
return parent::render($request, $exception);
190+
}
191+
```
192+
2.可自定义错误的异常设置
193+
配置文件`laravel_api.php`,在`exception.do_report`加入需要拦截的异常,示例:
194+
```
195+
'exception' => [
196+
'do_report'=>[
197+
UnauthorizedHttpException::class => [
198+
'msg' => '未授权或Token签名失效', // message显示的消息
199+
'http_code' => 401 // http状态码,不填则获取异常类的状态码,如果获取不到则500
200+
],
201+
AuthenticationException::class => [
202+
'msg' => '未授权或Token签名失效',
203+
'status_code' => 104013 // 响应体中code代码,可用于业务标识
204+
]
205+
]
206+
]
207+
```
208+
209+
### 4.jwt-auth
210+
> jwt-auth的详细介绍分析可以看 [JWT超详细分析](https://learnku.com/articles/17883) 这篇文章,具体使用可以看 [JWT完整使用详解](https://learnku.com/articles/10885/full-use-of-jwt) 这篇文章。
211+
212+
213+
1.打开 config 目录下的 app.php文件,添加服务提供者
214+
```
215+
'providers' => [
216+
...
217+
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
218+
]
219+
```
220+
2.发布配置文件
221+
```shell
222+
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
223+
```
224+
> 此命令会在 config 目录下生成一个 `jwt.php` 配置文件,你可以在此进行自定义配置。
225+
226+
3.生成密钥
227+
```shell
228+
php artisan jwt:secret
229+
```
230+
> 此命令会在你的 `.env` 文件中新增一行 `JWT_SECRET=secret`。以此来作为加密时使用的秘钥。
231+
232+
4.配置 Auth guard. 打开 `config` 目录下的 `auth.php`文件,修改api的驱动为`jwt`。这样,我们就能让api的用户认证变成使用jwt。
233+
```
234+
'guards' => [
235+
'web' => [
236+
'driver' => 'session',
237+
'provider' => 'users',
238+
],
239+
'api' => [
240+
'driver' => 'jwt',
241+
'provider' => 'users',
242+
],
243+
],
244+
```
245+
246+
5.更改 User Model
247+
如果需要使用`jwt-auth`作为用户认证,我们需要对我们的 User模型进行一点小小的改变,实现一个接口,变更后的`User`模型如下
248+
```php
249+
class User extends Authenticatable implements JWTSubject
250+
{
251+
...
252+
253+
public function getJWTIdentifier()
254+
{
255+
return $this->getKey();
256+
}
257+
public function getJWTCustomClaims()
258+
{
259+
return [];
260+
}
261+
}
262+
```
263+
264+
### 5.自动刷新用户认证 && 多看守器不串号 && 单一设备登陆
265+
现在我想用户登录后,为了保证安全性,每个小时该用户的token都会自动刷新为全新的,用旧的token请求不会通过。我们知道,用户如果token不对,就会退到当前界面重新登录来获得新的token,我同时希望虽然刷新了token,但是能否不要重新登录,就算重新登录也是一周甚至一个月之后呢?给用户一种无感知的体验。
266+
267+
1.增加中间件别名
268+
打开 app/Http 目录下的 Kernel.php 文件,添加如下一行
269+
```
270+
protected $routeMiddleware = [
271+
......
272+
'api.refresh'=>\Cyd622\LaravelApi\Middleware\RefreshTokenMiddleware::class,
273+
];
274+
```
275+
2.路由器修改
276+
```
277+
Route::middleware('api.refresh')->group(function () {
278+
// jwt认证路由以及无感刷新路由
279+
...
280+
});
281+
```
282+
3.登录控制器引入`LoginActionTrait`
283+
```
284+
class LoginController extends Controller
285+
{
286+
use LoginActionTrait;
287+
...
288+
}
289+
```
290+
4.原理
291+
292+
* 自动刷新用户认证
293+
> * 捕获到了 token 过期所抛出的 TokenExpiredException异常
294+
> * 刷新用户的 token `$token = $this->auth->refresh();`
295+
> * 使用一次性登录以保证此次请求的成功
296+
> * `Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);`
297+
> * 在响应头中返回新的 token `$this->setAuthenticationHeader($next($request), $token);`
298+
299+
* 多看守器不串号
300+
> * 我们通过Auth::claims() 添加自定义参数,在中间件时候进行解析,拿到我们的载荷,就可以进行判断是否是属于当前`guard`的token了。
301+
302+
* 单一设备登陆
303+
> * 我们将`token`都存到**缓存中**。在登陆接口,获取到`last_token`里的值,将其加入黑名单。
304+
> * 这样,只要我们无论在哪里登陆,之前的`token`一定会被拉黑失效,必须重新登陆,我们的目的也就达到了。

composer.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "cyd622/laravel-api",
3+
"description": "Laravel开发API助手",
4+
"keywords": [
5+
"laravel",
6+
"api"
7+
],
8+
"license": "MIT",
9+
"authors": [
10+
{
11+
"name": "cyd622",
12+
"email": "luffywang622@gmail.com"
13+
}
14+
],
15+
"require": {
16+
"php": ">=7.1",
17+
"tymon/jwt-auth": "1.0.0-rc.4.1"
18+
},
19+
"autoload": {
20+
"psr-4": {
21+
"Cyd622\\LaravelApi\\": "src/"
22+
}
23+
},
24+
"autoload-dev": {
25+
"psr-4": {
26+
"Cyd622\\LaravelApi\\Tests\\": "tests/"
27+
}
28+
},
29+
"extra": {
30+
"laravel": {
31+
"providers": [
32+
"Cyd622\\LaravelApi\\ApiServiceProvider"
33+
]
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)