@artman328
2021-07-15T02:45:27.000000Z
字数 6271
阅读 1878
Laravel
Sanctum
Restful
用 composer 建立一个 Laravel 项目:
composer create-project --prefer-dist laravel/laravel my-project
在控制台(或命令窗口)执行以下命令:
mysqladmin -uroot -p create database 'mydb'
然后编辑 .env 文件中的以下部分内容:
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=mydb
DB_USERNAME=root
DB_PASSWORD=[您的登录密码]
...
在控制台的项目文件夹中逐条执行以下命令:
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
位置:database/migrations/xxxx_xx_xx_xxxxxx_create_users_table.php
修改成以下代码(当然您可以根据自己需要进行增减字段):
<?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->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
在控制台项目文件夹中执行:
php artisan migrate
如果不成功,请根据输出自行排错。
位置:app/models/User.php
修改成以下代码(如果您的字段有所不同,作相应修改即可):
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable, hasApiTokens;
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
];
}
在控制台项目文件夹执行(您可以根据自己的需要确定控制器名,在此我用 AuthController):
php artisan make:controller AuthController
然后在控制器:app/Http/Controllers/AuthController.php 中添加四个方法如下:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use \Illuminate\Support\Facades\Cookie;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Symfony\Component\HttpFoundation\Response;
class AuthController extends Controller
{
// 用于注册用户
public function register(Request $req){
}
// 用于登录
public function login(Request $req){
}
// 用于获取当前登录用户
public function user(Request $req){
}
// 用于登出
public function logout(){
}
}
位置:app/routes/api.php
内容如下:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
// 以下两个路由公开
Route::post('/register',[\App\Http\Controllers\AuthController::class,'register']);
Route::post('/login',[\App\Http\Controllers\AuthController::class,'login']);
// 以下两个路由被保护(必须登录成功才能正常访问)
Route::middleware('auth:sanctum')->group(function(){
Route::get('/user',[\App\Http\Controllers\AuthController::class,'user']);
Route::post('/logout',[\App\Http\Controllers\AuthController::class,'logout']);
});
// 用于注册用户
public function register(Request $req){
return User::create([
'name' => $req->get('name'),
'email' => $req->get('email'),
'password'=>Hash::make($req->get('password'))
]);
}
然后在控制台项目文件夹中用以下命令启动服务器:
php artisan serve
再用 POSTMAN 对注册用户进行测试。
方法:POST
URL: http://localhost:8000/api/register
Header 设置:
键(KEY)'Accept',值(VALUE):'application/json'
BODY 选 'raw', 最右侧下拉框选 'JSON', 然后在输入框中输入注册用户信息如:
{
"name":"John",
"email":"john@theserver.com",
"password":"john-john"
}
设定好后点击 "Send", 正常应当返回如下结果:
{
"name": "John",
"email": "john@theserver.com",
"id": 1
}
// 用于登录
public function login(Request $req){
if(!Auth::attempt($req->only(['email','password']))){
return response(["msg"=>"Bad Credential"],Response::HTTP_UNAUTHORIZED);
}
// 创建 token,这个token 会被 sanctum 存入数据库表 personal_access_tokens
$token = Auth::user()->createToken($req->get('email'))->plainTextToken;
$cookie = cookie('token',$token,60*24); // 用 cookie 带到客户端
return response(['token'=>$token])->withCookie($cookie);
}
用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json)。
// 用于获取当前登录用户
public function user(Request $req){
return Auth::user();
}
用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json,Authorization 为'Bearer[空格]'+登录时获得的 token)。
// 用于登出
public function logout(){
//如果不再使用当前token,可用以下语句删除:
// Auth::user()->currentAccessToken()->delete();
$cookie = Cookie::forget("token");
return response(['msg'=>'Success'])->withCookie($cookie);
}
用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json,Authorization 为'Bearer[空格]'+登录时获得的 token)。
在服务器端检测请求,如果 cookie 中带有 token,则自动加载 token 到头部的 Authorization,可省去有cookie时在客户端设定 Authorization 为 Bearer [token] 的麻烦。
在 app/Http/Middleware/Authenticate.php 中加入以下方法。
public function handle($request, Closure $next, ...$guards)
{
if($token=$request->cookie('token')){
$request->headers->set('Authorization','Bearer '.$token);
}
$this->authenticate($request,$guards);
return $next($request);
}
为保证正常工作,客户端对API请求应当设定 Accept 为 application/json。为省去在客户端设定的麻烦,可在服务器端进行设定。这可以采用中间件的方法,也可采用在服务提供者的注册方法中修改请求并重新绑定到容器的方法。我们采用后一种。
在此必须注意,因为 Laravel 对 Request 对象的 Accept 在首次读取后会进行缓存,缓存后再设定 Accept 就不起作用了,因此应当保证在 Laravel 首次读取请求头时就设定好,这就是我采用第二种方法的原因。
将 app/Providers/AppProvider.php 修改成以下代码:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->addAcceptableJsonType();
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
}
protected function addAcceptableJsonType()
{
$this->app->rebinding('request', function ($app, $request) {
if ($request->is('api/*')) {
$accept = $request->header('Accept');
if (! str_contains($accept, '/json') || !str_contains($accept,'+json')) {
$accept = rtrim('application/json,'.$accept, ',');
$request->headers->set('Accept', $accept);
// 顺手设定一下服务器的 HTTP_ACCEPT,可以不要,只是以防用到此信息
$request->server->set('HTTP_ACCEPT', $accept);
$_SERVER['HTTP_ACCEPT'] = $accept;
}
}
});
}
}
Laravel Sanctum 是一个很好的验证框架,对 API 的身份验证非常便利。
直接调用 Auth::attempt() 方法即可验证身份(默认用 email 和 password 验证,也可自行修改使用其它信息)。
使用
Auth::user()->createToken("token名",[能力])->plainTextToken;
即可获得 token,并在数据库中保存 token 的哈希值。一个用户可创建多个 token,并对 token 指定其对资源的访问能力。