Lumen - 学习/实践

1.应用场景

学习使用Lumen框架,开发API服务,比如为App提供REST API服务,

以及实现微服务架构~

2.学习/操作

1.文档阅读

Lumen - PHP Micro-Framework By Laravel
Lumen - 为速度而生的 Laravel 框架 - Laravel 中国

Installation - Lumen - PHP Micro-Framework By Laravel
Lumen - 基于 Laravel 构建的最快的 PHP 微框架(Micro-Framework)。 | Laravel 中文网

2.整理输出

Note // 下面是几年前自己的学习体会

首先, 要即将学习的东西, 分为几部分, 快速地浏览一遍.

心中有个印象即可------基本思想: 这是啥, 能干啥[what-why]

后面再详细看, 认真看------基本思想:怎么干[how]

整个过程的基本思想:

这是啥,能干啥,怎么干. [what-why-how]

2.1 介绍

Lumen是一个基于Laravel的微框架,号称是以速度为生。

截用Lumen官网的一段,号称是比silex和slim还要快

2.2 实操

本文将用Lumen来实现一个完整的用户注册、登录及获取用户信息的API 【REST API

环境

Mac Pro

Homestead

Lumen 5.6

Lumen 8.x

Postman

方式一:

直接使用已有的项目进行测试 // 最后的测试是一样

Lumen 5.6

Code:

https://github.com/ningxiaofa/todo-app-with-lumen

https://github.com/ahmedkhan847/todoappwithlumen // 原始代码仓库

方式二:

使用Lumen 8.x重新构建

1. 构建项目,以及设置环境配置

composer create-project --prefer-dist laravel/lumen todorest

框架默认使用homestead环境, 比如数据库

Homestead

连接数据库

tablePlus 

Navicat

 

这里需要姜.env文件中的DB_HOST修改为: 192.168.10.10

如此,环境与项目初步看都okay了~

--------------------------------------------开始实践项目--------------------------------------------

2. Setup Lumen to use Facade and Eloquent. 解开如下代码注释

$app->withFacades();

$app->withEloquent();

$app->register(App\Providers\AppServiceProvider::class);

$app->register(App\Providers\AuthServiceProvider::class);

$app->routeMiddleware([

'auth' => App\Http\Middleware\Authenticate::class,

]);

3. 创建数据表[创建数据库迁移文件]

进入目录 database/migrations

创建文件

执行迁移命令,生成数据表

4. Create the User & ToDo Model

Users.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

use Illuminate\Contracts\Auth\Authenticatable;

use Illuminate\Auth\Authenticatable as AuthenticableTrait;

class Users extends Model implements Authenticatable
{
    use AuthenticableTrait;

    protected $fillable = ['username','email','password','userimage'];

    protected $hidden = [

        'password'

    ];

    /*

    * Get Todo of User

    */

    public function todo()

    {

        return $this->hasMany('App\Todo','user_id');

    }

}

Todo.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
    protected $table = 'todo';
    protected $fillable = ['todo','category','user_id','description'];

}

5. 创建User控制器

cd app/Http/Controllers

UsersController.php

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use App\Users;

class UsersController extends Controller
{
  public function __construct()
  {
    //  $this->middleware('auth:api');
  }

  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function authenticate(Request $request)
  {
    $this->validate($request, [
      'email' => 'required',
      'password' => 'required'
    ]);
    //  dd($request->all());
    $user = Users::where('email', $request->input('email'))->first();
    // Prevent from appearing error when user does not exist
    if (empty($user)) {
      return response()->json(['status' => 'fail', 'msg' => 'The user does not exist.'], 401);
    }
    if (Hash::check($request->input('password'), $user->password)) {
      $apikey = base64_encode(str_random(40));
      // dd($apikey); // Y0RDZE1FTDlaczFMdW5OcGVhTmhyT05LOW8yRjNkTVJQOFZqQ2o1TA==
      Users::where('email', $request->input('email'))->update(['api_key' => "$apikey"]);;
      return response()->json(['status' => 'success', 'api_key' => $apikey]);
    } else {
      return response()->json(['status' => 'fail', 'msg' => 'Email or password is not correct.'], 401);
    }
  }

  /**
   * User register
   * For ref: vendor/illuminate/database/Eloquent/Builder.php
   */
  public function register(Request $request)
  {
    // Validate params of user submited
    $this->validate($request, [
      'name' => 'required',
      'email' => 'required',
      'password' => 'required',
    ]);

    // Judgement: unique of email and name
    $user = Users::where('email', $request->input('email'))
    ->orWhere('name', $request->input('name'))
    ->first();
    if($user){
      return response()->json(['status' => 'fail', 'msg' => 'Name or email exists already.']);
    }

    // Store user info
    $hashPwd = Hash::make($request->input('password'));
    $ret = Users::insert(array_merge($request->all(), ['password' => $hashPwd]));
    if($ret){
      return response()->json(['status' => 'success', 'msg' => 'Register successully']);
    }
    return response()->json(['status' => 'fail', 'msg' => 'Register failed, please try later']);
  }
}

6. Update the Auth Service Provider

head to the app/Providers and open AutheServiceProvider.php file.

boot()方法中,修改如下:

$this->app['auth']->viaRequest('api', function ($request) {
   if ($request->header('Authorization')) { 
        $key = explode(' ',$request->header('Authorization'));
        $user = Users::where('api_key', $key[1])->first();
        if(!empty($user)){
            $request->request->add(['userid' => $user->id]);
            
        }
        return $user;
    }           
});

 app/Http/Middleware folder and open Authenticate.php file

return response()->json(['error' => 'Unauthorized'], 401);

7. Create the ToDo Controller

TodoController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Todo;
use Auth;

class TodoController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */


    public function index(Request $request)
    {
        $todo = Auth::user()->todo()->get();
        return response()->json(['status' => 'success', 'result' => $todo]);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'todo' => 'required',
            'description' => 'required',
            'category' => 'required'
        ]);
        if (Auth::user()->todo()->Create($request->all())) {
            return response()->json(['status' => 'success']);
        } else {
            return response()->json(['status' => 'fail']);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $todo = Todo::where('id', $id)->get();
        return response()->json($todo);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $todo = Todo::where('id', $id)->get();
        return view('todo.edittodo', ['todos' => $todo]);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request, [
            'todo' => 'filled',
            'description' => 'filled',
            'category' => 'filled'
        ]);
        $todo = Todo::find($id);
        if ($todo->fill($request->all())->save()) {
            return response()->json(['status' => 'success']);
        }
        return response()->json(['status' => 'failed']);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        if (Todo::destroy($id)) {
            return response()->json(['status' => 'success']);
        }
    }
}
 

8. Create Routes For the Todo API

$app->group(['prefix' => 'api/'], function ($app) {
    $app->get('login/','UsersController@authenticate');
    $app->post('todo/','TodoController@store');
    $app->get('todo/', 'TodoController@index');
    $app->get('todo/{id}/', 'TodoController@show');
    $app->put('todo/{id}/', 'TodoController@update');
    $app->delete('todo/{id}/', 'TodoController@destroy');
});

9. Test the ToDo REST API / 测试ToDo REST API

启动PHP内置HTTP Server

php -S localhost:8000 -t public

9.1 Register user

测试之前要先注册一个user用来测试

http://localhost:8000/api/register/?email=william@kumu.ph&password=Aa123456&name=william

数据表users

注册成功!

9.2 Login using the API

http://localhost:8000/api/login/

登录成功!

Note:

每次登录请求的响应如下:

{
    "status": "success",
    "api_key": "eng3MFRFeGZydWRrb3dMbW96ajV5Vm1seUlEV294OFV4cmZCVlBUNA=="
}

{
    "status": "success",
    "api_key": "clcwc1VvOEljekVCUkRPeDhyUTIwdmI4dG5wMlVyeDg0TWhBTlFTaA=="
}

可以知道,每次都会产生不同的token,而且写入数据库中,然后每次都要查询数据库进行验证~

这种方式在数据量小的时候,并没有什么问题,但是数据量大的时候,可能就需要采取一些优化措施。

所以是否支持session功能并不重要,PHP默认的session机制存储介质是文件,当然可以修改PHP配置文件,改存储到文件中为内存中,数据库中,Redis,甚至远端服务器中。

9.3 Create todo first

Note

认证信息可以放在在Authorization栏[postman专门独立出来放认证信息], 也可以放在请求头中。

前者[Authorization]

 后者[Request Header]

1. 测试没有添加认证的情况下,即不在请求头中带上api_key=OVRrUnVud1dFaEJQeUZJdjdsWVJCa1oyMDNEUXBKS1F4T3FsVjA1aA==

发起请求,查看结果: 未认证

2. 正常带上api_key

重新请求,查看返回结果

 请求体

payload: // content-type: json/application

{

"todo": "Testing REST Api",

"description": "Testing REST Api with Lumen",

"category": "REST"

}

数据表

创建todo成功 !

9.4 Get todo list

http://localhost:8000/api/todo

 获取列表成功!

9.5 Get one todo detail

http://localhost:8000/api/todo/1

获取todo详情成功! 

9.6 Update todo

http://localhost:8000/api/todo/1

数据表todo

更新成功! 

9.7 Delete todo

http://localhost:8000/api/todo/2

数据表todo

 删除成功!

 最后再获取列表

一切正常!

后续补充

...

3.问题/补充

1. 为什么Lumen认证使用的Bearer token类型验证?具体的配置地方在哪里?与其他认证方式有什么区别,或者说为什么选择了这种认证方式?

Authentication - Lumen - PHP Micro-Framework By Laravel

2. 这里的api_key是永久的,不会变的,也就意味着如果在App中,用户自己不主动退出,是一直保持登录状态的。当然也可能因为一些操作,到底api_key丢失的情况,则需要重新登录~

TBD

4.参考

就是上面的文档链接列表

Restful API - 学习/实践_william_n的博客-CSDN博客

后续补充

...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值