[关闭]
@artman328 2021-07-15T02:45:27.000000Z 字数 6271 阅读 1878

用 Laravel Sanctum 作 Restful API Token 认证## 标题

Laravel Sanctum Restful


一、首先建立 Laravel 项目

用 composer 建立一个 Laravel 项目:

  1. composer create-project --prefer-dist laravel/laravel my-project

二、建立数据库,并修改 .env 配置

在控制台(或命令窗口)执行以下命令:

  1. mysqladmin -uroot -p create database 'mydb'

然后编辑 .env 文件中的以下部分内容:

  1. ...
  2. DB_CONNECTION=mysql
  3. DB_HOST=127.0.0.1
  4. DB_PORT=3306
  5. DB_DATABASE=mydb
  6. DB_USERNAME=root
  7. DB_PASSWORD=[您的登录密码]
  8. ...

三、安装 laravel sanctum

在控制台的项目文件夹中逐条执行以下命令:

  1. composer require laravel/sanctum
  2. php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

四、修改用户表的迁移文件

位置:database/migrations/xxxx_xx_xx_xxxxxx_create_users_table.php
修改成以下代码(当然您可以根据自己需要进行增减字段):

  1. <?php
  2. use Illuminate\Database\Migrations\Migration;
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Support\Facades\Schema;
  5. class CreateUsersTable extends Migration
  6. {
  7. /**
  8. * Run the migrations.
  9. *
  10. * @return void
  11. */
  12. public function up()
  13. {
  14. Schema::create('users', function (Blueprint $table) {
  15. $table->id();
  16. $table->string('name');
  17. $table->string('email')->unique();
  18. $table->string('password');
  19. });
  20. }
  21. /**
  22. * Reverse the migrations.
  23. *
  24. * @return void
  25. */
  26. public function down()
  27. {
  28. Schema::dropIfExists('users');
  29. }
  30. }

五、迁移数据库

在控制台项目文件夹中执行:

  1. php artisan migrate

如果不成功,请根据输出自行排错。

六、修改用户(User)模型

位置:app/models/User.php
修改成以下代码(如果您的字段有所不同,作相应修改即可):

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Contracts\Auth\MustVerifyEmail;
  4. use Illuminate\Database\Eloquent\Factories\HasFactory;
  5. use Illuminate\Foundation\Auth\User as Authenticatable;
  6. use Illuminate\Notifications\Notifiable;
  7. use Laravel\Sanctum\HasApiTokens;
  8. class User extends Authenticatable
  9. {
  10. use HasFactory, Notifiable, hasApiTokens;
  11. public $timestamps = false;
  12. /**
  13. * The attributes that are mass assignable.
  14. *
  15. * @var array
  16. */
  17. protected $fillable = [
  18. 'name',
  19. 'email',
  20. 'password',
  21. ];
  22. /**
  23. * The attributes that should be hidden for arrays.
  24. *
  25. * @var array
  26. */
  27. protected $hidden = [
  28. 'password',
  29. ];
  30. /**
  31. * The attributes that should be cast to native types.
  32. *
  33. * @var array
  34. */
  35. protected $casts = [
  36. ];
  37. }

六、创建一个控制器进行身份验证

在控制台项目文件夹执行(您可以根据自己的需要确定控制器名,在此我用 AuthController):

  1. php artisan make:controller AuthController

然后在控制器:app/Http/Controllers/AuthController.php 中添加四个方法如下:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\User;
  4. use \Illuminate\Support\Facades\Cookie;
  5. use Illuminate\Http\Request;
  6. use Illuminate\Support\Facades\Auth;
  7. use Illuminate\Support\Facades\Hash;
  8. use Symfony\Component\HttpFoundation\Response;
  9. class AuthController extends Controller
  10. {
  11. // 用于注册用户
  12. public function register(Request $req){
  13. }
  14. // 用于登录
  15. public function login(Request $req){
  16. }
  17. // 用于获取当前登录用户
  18. public function user(Request $req){
  19. }
  20. // 用于登出
  21. public function logout(){
  22. }
  23. }

七、编写路由

位置:app/routes/api.php
内容如下:

  1. <?php
  2. use Illuminate\Http\Request;
  3. use Illuminate\Support\Facades\Route;
  4. /*
  5. |--------------------------------------------------------------------------
  6. | API Routes
  7. |--------------------------------------------------------------------------
  8. |
  9. | Here is where you can register API routes for your application. These
  10. | routes are loaded by the RouteServiceProvider within a group which
  11. | is assigned the "api" middleware group. Enjoy building your API!
  12. |
  13. */
  14. // 以下两个路由公开
  15. Route::post('/register',[\App\Http\Controllers\AuthController::class,'register']);
  16. Route::post('/login',[\App\Http\Controllers\AuthController::class,'login']);
  17. // 以下两个路由被保护(必须登录成功才能正常访问)
  18. Route::middleware('auth:sanctum')->group(function(){
  19. Route::get('/user',[\App\Http\Controllers\AuthController::class,'user']);
  20. Route::post('/logout',[\App\Http\Controllers\AuthController::class,'logout']);
  21. });

八、编写控制器中的注册方法

  1. // 用于注册用户
  2. public function register(Request $req){
  3. return User::create([
  4. 'name' => $req->get('name'),
  5. 'email' => $req->get('email'),
  6. 'password'=>Hash::make($req->get('password'))
  7. ]);
  8. }

然后在控制台项目文件夹中用以下命令启动服务器:

  1. php artisan serve

再用 POSTMAN 对注册用户进行测试。
方法:POST
URL: http://localhost:8000/api/register
Header 设置:
键(KEY)'Accept',值(VALUE):'application/json'
BODY 选 'raw', 最右侧下拉框选 'JSON', 然后在输入框中输入注册用户信息如:

  1. {
  2. "name":"John",
  3. "email":"john@theserver.com",
  4. "password":"john-john"
  5. }

设定好后点击 "Send", 正常应当返回如下结果:

  1. {
  2. "name": "John",
  3. "email": "john@theserver.com",
  4. "id": 1
  5. }

九、编写控制器中的登录方法

  1. // 用于登录
  2. public function login(Request $req){
  3. if(!Auth::attempt($req->only(['email','password']))){
  4. return response(["msg"=>"Bad Credential"],Response::HTTP_UNAUTHORIZED);
  5. }
  6. // 创建 token,这个token 会被 sanctum 存入数据库表 personal_access_tokens
  7. $token = Auth::user()->createToken($req->get('email'))->plainTextToken;
  8. $cookie = cookie('token',$token,60*24); // 用 cookie 带到客户端
  9. return response(['token'=>$token])->withCookie($cookie);
  10. }

用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json)。

十、编写控制器中获得当前用户的方法

  1. // 用于获取当前登录用户
  2. public function user(Request $req){
  3. return Auth::user();
  4. }

用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json,Authorization 为'Bearer[空格]'+登录时获得的 token)。

十一、编写控制器中退出登录方法

  1. // 用于登出
  2. public function logout(){
  3. //如果不再使用当前token,可用以下语句删除:
  4. // Auth::user()->currentAccessToken()->delete();
  5. $cookie = Cookie::forget("token");
  6. return response(['msg'=>'Success'])->withCookie($cookie);
  7. }

用 Postman 进行测试(头部设置别忘了设定 Accept 为 application/json,Authorization 为'Bearer[空格]'+登录时获得的 token)。

十二、服务器端自动加载 Authorization 信息(非必须)

在服务器端检测请求,如果 cookie 中带有 token,则自动加载 token 到头部的 Authorization,可省去有cookie时在客户端设定 Authorization 为 Bearer [token] 的麻烦。

在 app/Http/Middleware/Authenticate.php 中加入以下方法。

  1. public function handle($request, Closure $next, ...$guards)
  2. {
  3. if($token=$request->cookie('token')){
  4. $request->headers->set('Authorization','Bearer '.$token);
  5. }
  6. $this->authenticate($request,$guards);
  7. return $next($request);
  8. }

十三、服务器端设定 Accept(非必须)

为保证正常工作,客户端对API请求应当设定 Accept 为 application/json。为省去在客户端设定的麻烦,可在服务器端进行设定。这可以采用中间件的方法,也可采用在服务提供者的注册方法中修改请求并重新绑定到容器的方法。我们采用后一种。
在此必须注意,因为 Laravel 对 Request 对象的 Accept 在首次读取后会进行缓存,缓存后再设定 Accept 就不起作用了,因此应当保证在 Laravel 首次读取请求头时就设定好,这就是我采用第二种方法的原因。

将 app/Providers/AppProvider.php 修改成以下代码:

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\ServiceProvider;
  4. class AppServiceProvider extends ServiceProvider
  5. {
  6. /**
  7. * Register any application services.
  8. *
  9. * @return void
  10. */
  11. public function register()
  12. {
  13. $this->addAcceptableJsonType();
  14. }
  15. /**
  16. * Bootstrap any application services.
  17. *
  18. * @return void
  19. */
  20. public function boot()
  21. {
  22. }
  23. protected function addAcceptableJsonType()
  24. {
  25. $this->app->rebinding('request', function ($app, $request) {
  26. if ($request->is('api/*')) {
  27. $accept = $request->header('Accept');
  28. if (! str_contains($accept, '/json') || !str_contains($accept,'+json')) {
  29. $accept = rtrim('application/json,'.$accept, ',');
  30. $request->headers->set('Accept', $accept);
  31. // 顺手设定一下服务器的 HTTP_ACCEPT,可以不要,只是以防用到此信息
  32. $request->server->set('HTTP_ACCEPT', $accept);
  33. $_SERVER['HTTP_ACCEPT'] = $accept;
  34. }
  35. }
  36. });
  37. }
  38. }

十四、总结

Laravel Sanctum 是一个很好的验证框架,对 API 的身份验证非常便利。

直接调用 Auth::attempt() 方法即可验证身份(默认用 email 和 password 验证,也可自行修改使用其它信息)。
使用

  1. Auth::user()->createToken("token名",[能力])->plainTextToken;

即可获得 token,并在数据库中保存 token 的哈希值。一个用户可创建多个 token,并对 token 指定其对资源的访问能力。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注