欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

laravel 开发 restfulAPI

一、生成测试数据

 

首先建立表,建立model,建立controller。

然后使用faker自动生成数据。

database--factories--ModelFactory.PHP

$factory ->define(App\Lesson::class,function(Faker\Generator $faker){

return [

'title' = > $faker->sentence,

'body' =>$faker->paragraph,

'free' => $faker->boolean();

];

});

php artisan tinker

namespace App;

factory(Lesson::class,60)->create();//生成60条数据

 

二、初步实现API系统

 

1.路由:

Routes::group(['prefix' => 'api/v1'], function(){

Route::resource('lessons','LessonsController');

});

php artisan route:list;//查看路由

2.返回JSON格式

return Lesson::all();

$lesson=Lesson::findOrFail($id); return $lesson;

//return 会自动转换为JSON格式

3.在Model文件中

protected $hidden = ['title'];//禁止输出某些属性

4.直接return问题

1)暴露数据结构

2)没有错误提示

三、API字段映射

1.增加提示消息

return \Response::json([

'status'=>'success',

'status_code'=> 200,

'data'  =>$lessons->toArray();

]);

2.防止暴露数据库表结构

'data' => $this->transform($lessons);

private function transformCollection($lessons)

{

return array_map([$this,'transform'],$lessons->toArray());

}

 

private function transform($lesson)

{

return[

'title' =>$lesson['title'],

'content' => $lesson['body'],

'is_free' => (boolean)$lesson['free']

];

}

 

然后就可以隐藏结构,比如'body'包装成了'content'。然后返回时只要这样:

 

return \Response::json([

'status'=>'success',

'status_code'=> 200,

'data'  =>transformCollection(Lesson::all());//index方法中

//or:

'data'  =>transform(Lesson::find($id));//show方法中

]);

 

 

四、重构API代码

 

如果将transform和transformCollection放在Controller中,每增加一个Controller中,就需要加两个方法。。。

这种明显可以通过继承来优化,接下来看怎么做:

1.多个model的transformCollecion与transform怎么样避免重复

APP建立一个新的目录Transformer

新建Transformer.php

abstract class Transformer{

public function transformCollection($items)

{

return array_map([$this,'transform'],$items); 

}

public abstract transfomer($item);

}

新建LessonTransfomer

class LessonController extends Controller{

public function transfome($lesson)

 

{

return[

'title' =>$lesson['title'],

'content' => $lesson['body'],

'is_free' => (boolean)$lesson['free']

];

}

}

2.LessonsController中作相应修改

class LessonsController extends Controller

{

//添加一个依赖注入

protected $lessonTransformer;

public function __construct(LessonTransformer $lessonTransformer)

{

$this->lessonTransformer = $lessonTransformer;

}

//然后在本函数中直接用,比如:

$this->lessonTransformer->transfomerCollection($lessons);

}

composer dump-autoload//自动加载文件重新编译,重新加载

 

五、控制返回错误信息

 

1.创建一个ApiController

包含一些response(),responseError()等方法

2.LessonsController 继承ApiController

class ApiController extends Controller

{

protected $statuscode=200;

phpstorm可以快捷创建setter,getter

public function getStatusCode(){

return $this->statuscode;

}

public function setStatusCode($code){

$this->statuscode=$code;

return $this;//这样在方法中可以用链式操作,比如$this->setStatusCode(404)->responseNotFound();

}

public function responseNotFound($message = 'Not Found'){

return $this->responseError($message);

};

public function responseError($message){

return $this->response([

'status' = > 'failed',

'error' => [

'status_code' = > $this->getStatusCode(),

'message'=>$message

]

]);

};

public function response($data){

return \Response::json($data,$this->getStatusCode());

};

}

3. HTTP返回码得意义:

1**:hold on 持续请求中

2**:here you Go 正常返回

3**:go away重定向

4**: you fucked up 客户端请求故障

5**: I fucked up 服务器端故障

 

六、对请求API的用户认证

 

认证的引出——对于POST请求,为安全性我们不能允许响应所有人的请求,因此要作认证。

 

用google的POSTMAN来进行POST请求,以供测试

注意到提交POST时,WEB用FORM表单提交POST,API测试可以用POSTMAN

Routes::resource方法生成的post操作对应的是store方法。

注释掉Http下的Kernel.php中的$middleware \App\Http\Middleware\VerifyCsrfToken::class,才可以相应Post

种认证方法:baseAuth,Auth2.0, JWT.

这里先介绍baseAuth

1.在Controller的构造函数中:

$this->middleware('auth.basic',['only'=>['store','update']]);//即指明store方法需要验证,默认以User表为准

2.在store函数中:

public function store(Request)

{

if(!$request->get('title') or !$request->get('body')){

return $this->setStatucCode(422)->responseError('validate fails');

}

Lesson::create($request->all());//不要忘记去Model文件中修改权限$fillable

return $this->setStatusCode(201)->response([

'status'=>'success',

'message'=>'lesson created'

]);

}

七、安装DingoAPI和jwt-auth

两个项目在github中直接搜即可

1.通过composer安装DingoAPI,在require中添加

"require":{

"dingo/api": "1.0.*@dev",

"tymon/jwt-auth": "0.5.*"

}

composer update

配置DingoAPI

config--app.php的provider中添加:

'provider' => [Dingo\Api\Provider\LaravelServiceProvider::class]

php artisan vendor:publish --provider=Dingo\Api\Provider\LaravelServiceProvider'

这时在config文件夹下生成了api.php

 2.安装JWT-AUTH,直接看

 https://github.com/tymondesigns/jwt-auth/wiki/Installation

 在$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServ之后会在config文件夹下生成jwt.php

 在$ php artisan jwt:generate之后会生成一个随机的Key

八、Dingo API初探

按照github的wiki中的configuration来配置即可

将之前的transfomer用dingo/API来实现。

1.基本配置在.env中

API_STANDARDS_TREE=vnd

API_PREFIX=api

API_VERSION=v1

API_DEBUG=true

2.类似于前面的transformer类,dingo/api有TransFormerAbstract这个类。

  $this->collection($lessons, new AtransFormer());

九、JWT

1.建立一个api路由,register,login,利用JWT实现token,实现权限访问。

dingo/api函数:$this->item($lessons, new AtransFormer());

2.JWT用token来获得当前用户信息。

具体内容:

a.创建AuthController,定义authenticate函数,由mail和passwd返回token值

b.routes利用post访问Authcontroller的index方法,获得token

3. routesl增加middleware=》jwt.auth(在kernel文件中配置).

4.增加post路由获得register。同时在controller中增加register方法。

$user=User::create($newUser);

$token=JWTAuth::fromUser($user);

return response()->json(compact('token'));

 

若将password字段改名为user_password,

a.需要在AuthController中修改authenticate方法 $credentials=['user_name'=>$request->get('user_email')];

b.需要在相应的usermodel中增加:getAuthPassword(){return $this->user_password;}

jwt中有一个getAuthenticateUser()方法,是通过token来获取用户

if(! $user = JWTauth::parseToken()->authenticate()){return ...}

十、OAuth2.0

从dingo/api的autheratic中找到OAuth2.0,然后找到相应的laravel5安装和配置方法即可。

https://github.com/dingo/api/wiki/Authentication

https://github.com/dingo/api/wiki/OAuth-2.0

https://github.com/lucadegasperi/oauth2-server-laravel/wiki/Laravel-5-Installation

最后会再config下生产能Oauth2.php

使用Oauth2.0,基本配置见:

https://github.com/lucadegasperi/oauth2-server-laravel/wiki/Implementing-an-Authorization-Server-wit...

注意中间会生成一堆表,建一个client model对应oauth_clients表。生成数据后,将client_id复制到oauth_client_endpoints表格中,并且填写下redirect_uri即可。

这里我们需要先在oauth_clients增加client_id,client_secret,还有oauth_client_endpoints的redirect_uri。

先用client_id, response_type=code, redirect_uri,user_id向oauth/authorize利用POST请求code(这里需要用户先登录,在路由中用Auth::user()->id获得用户id)

先利用client_id,client_secret, redirect_uri, grant_type=authorization_code, code向\oauth\token来申请access_token。然后就可以使用oauth的Middleware了。 

github例子中请求全过程:(这里是以已经登录为前提)

以下以User代表用户浏览器,Client 代表应用服务器client server,Open代表开放平台接口服务器。

1.User首先向Client发出访问第三方登录界面的请求,如本例中的get oauth/authorize,

2.Client返回Open的授权页面url(Open方提供服务的url,Client端需要预存),如本例中的oauth/authorization-form

3.User通过该url向Open发出GET

注意:本例实际上模拟了Client端与Open端的操作,因为这里是假设自己是Open端,所以需要对Client端进行模拟操作,1,2,3三步是User与Client的通信。

4.Open返回授权页面,比如这里的view(oauth.authorization-form)

5.在这个地方User如果没有在Open中登录,则需要先登录,需要先登录再授权,或者登录同时授权,本例假设已经登录。在这个view中,User可以点击agree或者deny,如果agree,则发出post请求给oauth/authorize,请求code

6.Open向redirect_url返回一个含有code的url

7.User跳转到6返回的url(含有code参数)中(注意这里的redirect_url是Client设置的,由client提供服务!)

8.Client提取url中的code后可以利用post向Open请求access_token,这里是向oauth/token这个路径(实际中这个路径需要Open方预先提供给Client

9.Open返回给Client相关信息,包括access_token, uid, expire_time等

10.Client对相关信息做处理。期间可以利用access_token获取Open的其他有权限资源。

11.Client将处理结果输出给User。

code方式详见下图,这里的图来自http://drops.wooyun.org/papers/598

来自 http://blog.csdn.net/dskwe/article/details/49912983

普通分类: