Laravel 通过 Passport 实现 API 请求认证
标签:
编程学习
PHP学习
在处理博客API,目前正在整理用户认证这一块,方式有很多种,我这里选择的是用 Passport 来实现,这是一个官方提供的基于 OAuth 2.0 的扩展包。
安装扩展包
使用 Composer 来安装 Passport 扩展包:
composer require laravel/passport
生成所需数据库表:
php artisan migrate
接下来运行如下 Artisan 生成秘钥及数据:
php artisan passport:install
该命令会在 storage 目录下生成 oauth-private.key 和 oauth-public.key 两个秘钥文件,用于安全令牌的加密解密, 然后在 oauth_clients 数据表中初始化两条记录,相当于注册了两个客户端应用,一个用于密码授权令牌认证,一个用于私人访问令牌认证。
模型及路由支持
如果要让用户支持 API 认证,需要在对应模型类中使用 Laravel\Passport\HasApiTokens Trait,里面包含了认证所需的方法,我这里只是用户类用到,所以需要修改 User 类:
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable {
use HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [];
}
Passport 为 API 认证提供了相应的路由,我们需要在 AuthServiceProvider 的 boot 方法中注册 API 认证相关路由:
// 顶部引入相应命名空间
use Laravel\Passport\Passport;
...
public function boot() {
...
// API 认证路由注册
Passport::routes();
}
将 config/auth.php 中的 API 认证驱动由 token 修改为 Passport:
'guards' => [
...
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
添加路由配置
Route::group(['namespace' => 'Api\v1', 'prefix' => 'v1'], function () {
//验证码,比较穷,所以暂时选择邮箱验证码
Route::get('sendCode', 'AuthController@sendCodeAction');
//登录相关
Route::post('login', 'AuthController@loginAction');
});
//API认证采用passport
Route::group(['namespace' => 'Api\v1', 'prefix' => 'v1', 'middleware' => 'auth:api'], function () {
Route::post('user', 'UserController@index');
});
实现登录
直接使用 Passport 提供的方法 createToken 创建 token
/// 登录
public function loginAction(Request $request) {
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->credentials($request);
if ($this->guard()->attempt($credentials)) {
//获取邮箱
$name = $request->get('username');
//删除当前用户之前的token
DB::table('oauth_access_tokens')->where('name', $name)->delete();
//添加新的token,token名字为手机号
$token = \Auth::getUser()->createToken($name)->accessToken;
//返回token
return ApiResponseBuilder::success($token);
} else {
return ApiResponseBuilder::errorWithMessage(200,'登录失败,请检查您的账号和密码',200);
}
}
然后我们就可以直接访问到用户信息了
/**
* 获取oauth认证之后的用户ID
* @return mixed
*/
public function getUserId() {
$user = \Auth::user();
if(!$user){
return ApiResponseBuilder::errorWithMessage(200, "error", 200);
}
return $user->getAuthIdentifier();
}
public function index(Request $request) {
try {
$id = $request->userid;
if(!$id){
$id = $this->getUserId();
}
$user = User::findOrFail($id);
return ApiResponseBuilder::success($user);
} catch (\Exception $e) {
return ApiResponseBuilder::errorWithMessage(200, "数据丢失", 200);
}
}
这里要注意,拼接 Authorization 的时候中间是两个空格,之前被这个坑过