Laravel Api实现JWT Token认证

发布日期: 2020-05-07 21:41:51 作者: Stephen 评论: 16

在开发Api时,处理客户端请求之前,需要对用户进行身份认证,Laravel框架默认为我们提供了一套用户认证体系,在进行web开发时,几乎不用添加修改任何代码,可直接使用,但在进行api开发时,需要我们自己去实现,并且Laravel框架默认提供的身份认证不是jwt的,需要在数据库中增加api_token字段,记录用户认证token并进行身份校验,如果需要使用jwt,无需添加字段,需要借助三方库来实现。

Token认证原理

  1. 客户端发送认证信息 (一般就是用户名 / 密码), 向服务器发送请求

  2. 服务器验证客户端的认证信息,验证成功之后,服务器向客户端返回一个 加密的 token (一般情况下就是一个字符串)

  3. 客户端存储 (cookie, session, app 中都可以存储) 这个 token, 在之后每次向服务器发送请求时,都携带上这个 token

  4. 服务器验证这个 token 的合法性,只要验证通过,服务器就认为该请求是一个合法的请求

JWT概述

token 只是一种思路,一种解决用户授权问题的思考方式,基于这种思路,针对不同的场景可以有很多种的实现。而在众多的实现中,JWT (JSON Web Token) 的实现最为流行.

JWT 这个标准提供了一系列如何创建具体 token 的方法,这些缘故方法和规范可以让我们创建 token 的过程变得更加合理和效率.

比如,传统的做法中,服务器会保存生成的 token, 当客户端发送来 token 时,与服务器的进行比对,但是 jwt 的不需要在服务器保存任何 token, 而是使用一套加密 / 解密算法 和 一个密钥 来对用户发来的 token 进行解密,解密成功后就可以得到这个用户的信息.

这样的做法同时也增加了多服务器时的扩展性,在传统的 token 验证中,一旦用户发来 token, 那么必须要先找到存储这个 token 的服务器是哪台服务器,然后由那一台服务器进行验证用户身份。而 jwt 的存在,只要每一台服务器都知道解密密钥,那么每一台服务器都可以拥有验证用户身份的能力.

这样一来,服务器就不再保存任何用户授权的信息了,也就解决了 session 曾出现的问题.

实现方法

1.安装 jwt-auth

composer require tymon/jwt-auth:dev-develop

参考文档:

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

2.在 config/app.phpproviders 配置项中注册服务提供者

Tymon\JWTAuth\Providers\LaravelServiceProvider::class,

3.生成配置文件

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

此命令会在 config 目录下生成 jwt.php 配置文件

4.生成密钥

php artisan jwt:secret

此命令会在你的 .env 文件中新增一行 JWT_SECRET=secret

5.创建模型

php artisan make:model Models/User

代码:

<?php

namespace App\Models;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{

    protected $fillable = ['name', 'password'];

    protected $hidden = ['password', 'remember_token'];

    //
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }
}

6.修改配置文件 auth.php

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

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

7.实现登录注册返回token

php artisan make:controller Api/UserController
<?php

namespace App\Http\Controllers\Api;

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

class PassportController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['register', 'login']]);
    }

    /**
    * 用户注册
    */
    public function register(Request $request)
    {
        // jwt token
        $credentials = [
            'name' => $request->name,
            'password' => Hash::make($request->password)
        ];
        $user = User::create($credentials);
        if($user){
            $token =  = JWTAuth::fromUser($user);
            return $this->responseWithToken($token);
        }
    }

    /**
    * 用户登录
    */
    public function login(Request $request)
    {
        // todo 用户登录逻辑

        // jwt token
        $credentials = $request->only('name', 'password');
        if (!$token = auth()->attempt($credentials)) {
            return response()->json(['result'=>'failed']);
        }
        return $this->responseWithToken($token);
    }

    /**
    * 刷新token
    */
    public function refresh()
    {
        return $this->responseWithToken(auth()->refresh());
    }

    /**
    * 退出登录
    */
    public function logout(Request $request)
    {
        auth()->logout();
    }

    /**
    * 响应
    */
    private function responseWithToken(string $token)
    {
        $response = [
            'access_token' => $token,
            'token_type' => 'Bearer',
            'expires_in' => auth()->factory()->getTTL() * 60
        ];

        return response()->json($response);
    }
}

充气龙飞 2年前
这个怎么解密
博主 2年前
@ 充气龙飞 auth()->id() 获取登录用户ID,auth()->user() 获取登录用户信息
南风雨琴 3年前
不使用attempt 使用login可以吗
博主 3年前
@ 南风雨琴 auth()->login(\Illuminate\Contracts\Auth\Authenticatable $user);
南风雨琴 3年前
’记住我‘ 可以实现吗? (每个用户不同的token有效期)
博主 3年前
@ 南风雨琴 可通过setTTL(30)方法为每个用户动态设置有效期:auth()->setTTL(30)->attempt($credentials, true);
南风雨琴 3年前
@ Stephen 不使用attempt 使用login可以吗
博主 3年前
@ 南风雨琴 auth()->login(\Illuminate\Contracts\Auth\Authenticatable $user)
南风雨琴 3年前
@ Stephen 测试一下可以了 感谢 感谢
东方小if 3年前
时间的控制么 怎么修改有效时长
博主 3年前
@ 东方小if config/jwt.php配置文件中修改配置ttl,默认60分钟
Eric 3年前
这样写怎么配置路由?
博主 3年前
@ Eric 路由都正常的配置
Jerry 4年前
写的很详细!
博主 4年前
@ Jerry 感谢支持!祝好!
感谢分享!!!