在 Laravel 中使用 JSON Web Tokens 创建 API
在 API 中使用 JWT 进行用户身份验证特别有用,因为它不需要在服务器上实现会话,而且 JWT 本身包含与发出请求的用户相对应的信息,可用于验证其真实性。
首先,我们需要安装 Laravel 并创建一个项目。安装 Laravel 5.8 的说明。安装 Laravel 后,我们继续创建一个项目。
$ laravel new webpage
要在 Laravel 中实现 JWT,我们将使用名为 tymondesigns/jwt-auth 的模块,使用以下代码:
$ composer require tymon/jwt-auth:dev-develop --prefer-source
然后要生成配置文件,我们运行以下代码:
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
我们继续为项目生成密钥:
$ php artisan jwt:secret
为了让 Laravel 自动连接到我们的数据库并将其用作用户验证方法,我们必须创建一个具有以下列的 users
表:
id
PRIMARY KEY AUTOINCREMENTname
VARCHARsurname
VARCHARemail
VARCHARpassword
VARCHARcreate_at
TIMESTAMPupdated_at
TIMESTAMP
默认情况下,User
模型将使用 users
表。如果要指定表的其他名称,可以在 app\User.php
中使用以下代码定义要使用的名称:
...
protected $table = ''; // 我们放入表名
...
以下步骤在代码级别。我们需要在 User
模型中实现 Tymon\JWTAuth\Contracts\JWTSubject
。在这个模型中,我们必须实现两个方法:getJWTIdentifier()
和 getJWTCustomClaims()
。
app\User.php
中的 User
模型应类似于:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject {
use Notifiable;
protected $fillable = [
'name', 'surname', 'email', 'password',
];
protected $hidden = [
'password','remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier() {
return $this->getKey();
}
public function getJWTCustomClaims() {
return [];
}
}
现在为了让 Laravel 使用 JWT 作为身份验证方法,我们打开 config/auth.php
文件并修改以下数据:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
现在我们继续添加身份验证控制器。我们将其称为 AuthController
。我们可以手动创建它,或使用以下命令:
$ php artisan make:controller AuthController
在这个控制器中,我们放入以下代码:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\RegisterAuthRequest;
use App\User;
use Illuminate\Http\Request;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthController extends Controller {
public $loginAfterSignUp = true;
public function register(Request $request) {
$user = new User();
$user->name = $request->name;
$user->surname = $request->surname;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->loginAfterSignUp) {
return $this->login($request);
}
return response()->json([
'status' => 'ok',
'data' => $user
], 200);
}
public function login(Request $request) {
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'status' => 'invalid_credentials',
'message' => 'Incorrect email or password.',
], 401);
}
return response()->json([
'status' => 'ok',
'token' => $jwt_token,
]);
}
public function logout(Request $request) {
$this->validate($request, [
'token' => 'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'status' => 'ok',
'message' => 'Logout successful.'
]);
} catch (JWTException $exception) {
return response()->json([
'status' => 'unknown_error',
'message' => 'The user could not be logged out.'
], 500);
}
}
public function getAuthUser(Request $request) {
$this->validate($request, [
'token' => 'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}
}
现在我们在 routes\api.php
中创建将访问这些方法的路由:
<?php
use Illuminate\Http\Request;
// 这些路由可以在不提供有效令牌的情况下访问。
Route::post('/login','AuthController@login');
Route::post('/register','AuthController@register');
// 这些路由需要一个有效的令牌才能被访问。
Route::group(['middleware' => 'auth.jwt'], function () {
Route::post('/logout', 'AuthController@logout');
});
此外,我们可以在 public\index.php
的开头添加以下代码,以避免在测试期间发生 CORS 错误:
// 允许来自任何来源的请求
header('Access-Control-Allow-Origin: *');
// 允许使用 GET、PUT、POST、DELETE 和 OPTIONS 方法的请求
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
// 允许 Content-Type 和 Authorization 标头
header('Access-Control-Allow-Headers: Content-Type, Authorization');
这就结束了使用 JSON Web Tokens 的 Laravel 配置部分。现在我们继续使用 Insomnia 进行一些测试请求,以验证我们的路由是否正常工作。
我们向 /api/register
路由发出请求,并确认我们收到一个 status
: ok
和一个 token
。
这意味着该用户已在数据库中注册,并且自动生成了一个令牌,我们必须在每个受保护路由请求中发送该令牌。
我们还可以测试 /api/login
。
令牌可以通过不同的方式在每个请求中发送:
- 我们可以在使用
GET
的情况下通过 url 发送,例如.../api/products?token=eyJ0eXAiOiJ...
。 - 作为在
POST
中发送的 JSON 的一个属性。 - 或者作为
Authorization: Bearer eyJ0eXAiOiJ...
标头的一部分。
在下面的示例中,我们将其作为 JSON 中的一个属性发送,以使用 api/logout
注销用户。
以同样的方式,我们可以继续创建更多需要有效令牌才能访问的受保护路由。像往常一样,任何问题都可以留在评论中。祝好。