Lumen上使用Dingo/Api作API开发时用JWT-Auth作认证的实现

 Lumen轻量级的框架,用来作API很合适,起码本人这么想。javascript

作API,能够配合Dingo/Api来搞。php

Dingo/Api可使用的用户认证方式有:java

  • HTTP Basic (Dingo\Api\Auth\Provider\Basic)
  • JSON Web Tokens (Dingo\Api\Auth\Provider\JWT)
  • OAuth 2.0 (Dingo\Api\Auth\Provider\OAuth2)
这里选了JWT来实现。

须要用的工具备:laravel

  • Lumen
  • Dingo/Api
  • Tymon/JWT-Auth

API能够简单的分三个部分:git

  • 登陆
  • 验证
  • 具体的API行为

因此,先从登陆开始。github


这里的API服务基于Lumen实现。Laravel的实现还没搞过,之后再说。数据库


1、Tymon/JWT-Auth安装json


一、Lumen环境下执行:bootstrap

composer require tymon/jwt-auth
而后须要添加“JWTAuthServiceProvider”到 Provider List。在Laravel环境中配置放在config/app.php中,但在Lumen环境有些不一样。


二、在"bootstrap/app.php" 文件中,找到Register Service Providers一节,添加:app

$app->register('Tymon\JWTAuth\Providers\JWTAuthServiceProvider');

3 、在“app”目录下建立“helpers.php”文件。

内容以下:

<?php

if ( ! function_exists('config_path'))  
{
    /**
     * Get the configuration path.
     *
     * @param  string $path
     * @return string
     */
    function config_path($path = '')
    {
        return app()->basePath() . '/config' . ($path ? '/' . $path : $path);
    }
}

修改composer.json文件。添加:

"autoload": {
    ...
    "files": [
      "app/helpers.php"
    ]
  },

执行:

composer dump-autoload

四、生成jwt-auth的配置文件

最简单的办法是从/vendor/tymon/jwt-auth/src/config/config.php 复制一份到config/jwt.php。

由于lumen没有vendor:publish命令,因此,能够装basicit/lumen-vendor-publish来解决。

composer require basicit/lumen-vendor-publish

而后执行:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

会以config目录下生成jwt.php文件。这就是jwt-auth的配置文件。

执行“php artisan jwt:generate ”生成secret。


五、Adding facades

a)bootstrap/app.php文件中去掉"$app->withFacades();"前的注释。

b)在这行下面添加“$app->configure('jwt');”,否则调用不到jwt的配置文件。

c)紧接着是facades。

class_alias('Tymon\JWTAuth\Facades\JWTAuth', 'JWTAuth');  
/** This gives you finer control over the payloads you create if you require it.
 *  Source: https://github.com/tymondesigns/jwt-auth/wiki/Installation
 */
class_alias('Tymon\JWTAuth\Facades\JWTFactory', 'JWTFactory'); // Optional

六、jwt的配置文件里保持默认就能够。想知道具体含义能够参考它的文档。secret是必须设的。前面已经设过了。

七、在bootstrap/app.php文件中,查找Register Middleware 小节。去掉"routeMiddleware"的注释,修改为下面这样:

$app->routeMiddleware([
    'jwt.auth'    => Tymon\JWTAuth\Middleware\GetUserFromToken::class,
    'jwt.refresh' => Tymon\JWTAuth\Middleware\RefreshToken::class,
]);


八、此时,可使用路由中间件了。下面举个例子。

<pre name="code" class="php">// store, update, destory这些须要权限的操做所有须要通过认证。
$app->group(['prefix' => 'projects', 'middleware' => 'jwt.auth'], function($app) { $app->post('/', 'App\Http\Controllers\ProjectsController@store'); $app->put('/{projectId}', 'App\Http\Controllers\ProjectsController@update'); $app->delete('/{projectId}', 'App\Http\Controllers\ProjectsController@destroy');}); // index, show这些则不须要$app->group(['prefix' => 'projects'], function ($app){ $app->get('/', 'App\Http\Controllers\ProjectsController@index'); $app->get('/{projectId}', 'App\Http\Controllers\ProjectsController@show');});
 

九、登陆。下面要作的就是写一个登陆的程序,由于lumen没有,要本身写。

建一个路由“$app->post('auth/login', 'App\Http\Controllers\Auth\AuthController@postLogin');”

在“app/Http/Controllers/Auth/AuthController.php”中建立咱们的登陆代码。

示例以下:

<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Exception\HttpResponseException;  
use JWTAuth;  
use Tymon\JWTAuth\Exceptions\JWTException;  
use App\Http\Controllers\Controller;  
use Illuminate\Http\Request;  
use Illuminate\Http\Response as IlluminateResponse;

class AuthController extends Controller {

    /**
     * Handle a login request to the application.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function postLogin(Request $request)
    {
        try
        {
            $this->validate($request, [
                'email' => 'required|email|max:255', 'password' => 'required',
            ]);
        }
        catch (HttpResponseException $e)
        {
            return response()->json([
                'error' => [
                    'message'     => 'Invalid auth',
                    'status_code' => IlluminateResponse::HTTP_BAD_REQUEST
                ]],
                IlluminateResponse::HTTP_BAD_REQUEST,
                $headers = []
            );
        }

        $credentials = $this->getCredentials($request);

        try
        {
            // attempt to verify the credentials and create a token for the user
            if ( ! $token = JWTAuth::attempt($credentials))
            {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        }
        catch (JWTException $e)
        {
            // something went wrong whilst attempting to encode the token
            return response()->json(['error' => 'could_not_create_token'], 500);
        }

        // all good so return the token
        return response()->json(compact('token'));
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function getCredentials(Request $request)
    {
        return $request->only('email', 'password');
    }
}
此时,用post方式提交一个登陆请求会获得json格式的返回值,里面就是登陆后得到的token.

{
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHA6XC9cLzEyNy4wLjAuMTo4NFwvYXV0aFwvbG9naW4iLCJpYXQiOiIxNDQ2OTE4MjM3IiwiZXhwIjoiMTQ0NjkyMTgzNyIsIm5iZiI6IjE0NDY5MTgyMzciLCJqdGkiOiI1ZGY1Njk5OGYxMTc3MzlhMjQ4ZjgzNzUyZmQ2MTA1MiJ9.1FP8yXwlw_KHrx9NAFqQWPaq2c2LLq_vyuJgwI_EX9k"
}

十、还要提一下,jwt-auth默认使用Users表作为登陆认证的表,这个表跟laravel是同样的。因此能够直接从laravel复制过来。

也能够另外指定。具体请看jwt.php中"User Model namespace" 的设置。

也就是,建立"User" model,生成数据库表users。再插入几条用户记录,到此项目完成。

可是!!!这里有个问题,User Model有些内容必需要有。

以下:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
    use Authenticatable, CanResetPassword;

    //use EntrustUserTrait; // add this trait to your user model

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'email', 'password'];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];
}
请跟本身的User Model对比一下。

出现以下错误通常都是User Model有问题。

Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\User given, called in C:\xampp\htdocs\APIs\vendor\illuminate\auth\Guard.php on line 390


另外,有条件的能够装个Postman。这个工具很是很是棒。



--完--