Lumen 8.0 使用 Jwt 认证的 Api

Lumen 8.0 使用 Jwt 认证的 Api

源代码参考

安装lumen

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

拷贝配置

copy .env.example .env

启动

php -S localhost:83 -t public

生成APP_KEY

由于lumenkey:generate命令,所以需要创建文件

<?php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;

class KeyGenerateCommand extends Command
{
    // 命令名
    protected $name = 'key:generate';
    // 描述
    protected $description = "Set the application key";
    // 执行
    public function handle() {
        $key = $this->getRandomKey();
        if ($this->option('show')){
            $this->line('<command>'.$key.'</command>');
            return;
        }
        $path = base_path('.env');
        if (file_exists($path)){
            file_put_contents($path, str_replace('APP_KEY='.env('APP_KEY'), 'APP_KEY='.$key, file_get_contents($path)));
        }
        $this->info("Application key [$key] set successfully.");
    }

    /**
     * @return string
     * 获取随机32key
     */
    protected function getRandomKey(){
        return Str::random(32);
    }

    protected function getOptions()
    {
        return [
            ['show', null, InputOption::VALUE_NONE, 'Simply display the key instead of modifying files.']
        ];
    }
}

添加命令到app/Console/Kernel.php文件中

<?php

namespace App\Console;

use App\Console\Commands\KeyGenerateCommand;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        KeyGenerateCommand::class
    ];
}

生成key

D:\phpstudy_pro\WWW\lumen>php artisan key:generate
Application key [wRtxrX9DZs8HlZ0WMERxHo43Mkjbev1l] set successfully.

修改配置

APP_NAME=Lumen
APP_ENV=local
APP_KEY=wRtxrX9DZs8HlZ0WMERxHo43Mkjbev1l
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=Asia/Shanghai

LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lumen
DB_USERNAME=root
DB_PASSWORD=phpTest1!

CACHE_DRIVER=file
QUEUE_CONNECTION=sync

安装jwt

composer require tymon/jwt-auth

配置启动文件

修改boostrap/app.php

<?php

require_once __DIR__.'/../vendor/autoload.php';

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__)
))->bootstrap();

date_default_timezone_set(env('APP_TIMEZONE', 'UTC'));

$app = new Laravel\Lumen\Application(
    dirname(__DIR__)
);

$app->withFacades();

$app->withEloquent();

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);

$app->configure('app');

// 认证中间件
 $app->routeMiddleware([
     'auth' => App\Http\Middleware\Authenticate::class,
 ]);

// $app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
// jwt注册
$app->register(\Tymon\JWTAuth\Providers\LumenServiceProvider::class);

$app->router->group([
    'namespace' => 'App\Http\Controllers',
], function ($router) {
    require __DIR__.'/../routes/api.php';
    require __DIR__.'/../routes/web.php';
});

return $app;

生成秘钥

php artisan jwt:secret

# 查看.env
JWT_SECRET=JGPUooBjSd2PI91nizCI10ZfI56yLsl9dg9GiUozf8pgjfOS9fPYeTpgVIJaSbBG

自定义响应格式

加载此文件,需要在composer.json添加一下代码

"autoload": {
        ...
        "files": [
            "app/Helpers/helper.php"
        ]
    },
<?php

/**
 * 响应格式
 */
if (!function_exists('resp')) {
    function resp($code = 200, $msg = '', $data = []) {
        return response()->json([
            'code'  => $code,
            'msg'   => $msg,
            'data'  => $data,
        ]);
    }
}

用户认证

使用make:migration 生成表

默认此文件已存在,如果不存在则创建

D:\phpstudy_pro\WWW\lumen>php artisan make:migration create_users_table --create=users
Created Migration: 2020_09_18_103745_create_users_table

定义表字段

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('username');
            $table->string('password');
            $table->string('email');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

数据迁移

D:\phpstudy_pro\WWW\lumen>php artisan migrate
Migrating: 2020_09_18_103745_create_users_table
Migrated:  2020_09_18_103745_create_users_table (280.89ms)
修改User模型
<?php

namespace App\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
    use Authenticatable, Authorizable, HasFactory;

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

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];

    /**
     * @inheritDoc
     * 获取jwt中的用户标识
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * @inheritDoc
     * 获取jwt中的用户自定义字段
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}
配置认证guard

拷贝vendor/laravel/lumen-framework/config/auth.phpconfig/目录下,并修改如下:

<?php

return [

    'defaults' => [
        'guard' => env('AUTH_GUARD', 'api')
    ],

    'guards' => [
        'api'   =>  [
            'driver' => 'jwt',
            'provider' => 'users'
        ]
    ],

    'providers' => [
        'users' => [
            'driver'    => 'eloquent',
            'model'     => \App\Models\User::class
        ]
    ],

    'passwords' => [
        //
    ],

];
定义路由文件api.php
<?php
/** @var \Laravel\Lumen\Routing\Router $router */

// 创建用户和登录
$router->group([
    'prefix' => 'auth',
    'namespace' => 'Api',
], function () use ($router) {
    $router->post('/store', 'UserController@store');
    $router->post('/login', 'UserController@login');
    $router->get('/user', 'UserController@index');
    $router->get('/me', 'UserController@me');
    $router->get('/logout', 'UserController@logout');
});
创建UserController
<?php
namespace App\Http\Controllers\Api;

use App\Exceptions\Code;
use App\Exceptions\Msg;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Controllers\Controller;

class UserController extends Controller
{

    /**
     * UserController constructor.
     * 认证中间件,排除登录和注册
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login','store']]);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * 所有用户
     */
    public function index() {
        $users = User::paginate(env('PAGINATE'));
        return resp(Code::Success, Msg::Success, $users);
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * 登录
     */
    public function login(Request $request) {
        $message = [
            'username.required' => "请输入用户名",
            'password.required' => "请输入密码",
        ];
        $validator = Validator::make($request->all(), [
            'username' => 'required',
            'password'  => 'required'
        ], $message);
        if ($validator->fails()) {
            foreach($validator->errors()->getMessages() as $error) {
                return resp(Code::LoginFailed, $error[0]);
            }
        }
        $credentials = request(['username', 'password']);
        if (! $token = auth()->attempt($credentials)) {
            return resp(Code::LoginFailed, Msg::LoginFailed);
        }
        return resp(Code::LoginSuccess, Msg::LoginSuccess, $this->responseWithToken($token));
    }

    /**
     * @param $token
     * @return array
     * 返回token信息
     */
    protected function responseWithToken($token) {
        return [
            'access_token' => $token,
            'token_type'    => 'bearer',
            'expires_in'    => auth()->factory()->getTTL() * env('JWT_TTL')
        ];
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * 创建用户
     */
    public function store(Request $request)
    {
        $message = [
            'email.required'    => '请输入邮箱',
            'email.email'       => '邮箱格式不正确',
            'email.unique'      => '邮箱已存在',
            'username.required' => '请输入用户名',
            'password.required' => '请输入密码',
            'username.min'      => '用户名至少 :min 位',
            'password.min'      => '密码至少 :min 位',
        ];
        $validator = Validator::make($request->input(), [
            'email' => 'required|email|unique:users',
            'username' => 'required|min:6',
            'password' => 'required|min:8',
        ], $message);

        if ($validator->fails()) {
            foreach($validator->errors()->getMessages() as $error) {
                return resp(Code::CreateUserFailed, $error[0]);
            }
        }
        $username = $request->get('username');
        $email = $request->get('email');
        $password = $request->get('password');

        $attributes = [
            'email' => $email,
            'username' => $username,
            'password' => app('hash')->make($password)
        ];
        $user = User::create($attributes);
        return resp(Code::CreateUserSuccess, Msg::CreateUserSuccess, $user);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * 当前用户信息
     */
    public function me() {
        return resp(Code::UserIsMe, Msg::UserIsMe, auth()->user());
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     * 退出登录
     */
    public function logout() {
        auth()->logout();
        return resp(Code::LoginOutSuccess, Msg::LoginOutSuccess);
    }

    /**
     * @return array
     * 刷新token
     */
    public function refresh(){
        return $this->responseWithToken(auth()->refresh());
    }
}
定义返回状态码和信息
<?php


namespace App\Exceptions;


class Code
{
    const   Success           = 200;
    const   Unauthorized      = 401;
    const   Failed            = 500;

    const   CreateUserSuccess = 10001;
    const   CreateUserFailed  = 10002;

    const   LoginSuccess      = 20001;
    const   LoginFailed       = 20002;
    const   LoginOutSuccess   = 20003;
    const   UserIsMe          = 20004;

    const   CreatePostsSuccess  =   30001;
    const   CreatePostsFailed   =   30002;
    const   PostsListSuccess    =   30003;
    const   PostsListFailed     =   30004;
}
<?php


namespace App\Exceptions;


class Msg
{
    const   Success           =   '成功';
    const   Unauthorized      =   '未认证';
    const   Failed            =   '失败';
    const   CreateUserSuccess =   '创建用户成功';
    const   CreateUserFailed  =   '创建用户失败';
    const   LoginSuccess      =   '登录成功';
    const   LoginFailed       =   '登录失败';
    const   LoginOutSuccess   =   '退出成功';
    const   UserIsMe          =   '获取当前用户';

    const   CreatePostsSuccess  =   '创建文章成功';
    const   CreatePostsFailed   =   '创建文章失败';
    const   PostsListSuccess    =   '查询文章列表成功';
    const   PostsListFailed     =   '查询文章列表失败';
}
测试创建用户

使用postman工具

创建用户
创建用户

登录用户
登录用户

当前用户
当前用户

用户列表
用户列表

退出登录
退出登录

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
39
粉丝
11
喜欢
71
收藏
102
排名:464
访问:1.9 万
私信
所有博文
社区赞助商