Laravel 5 API 对使用 Facebook 授权的移动应用程序的授权
Laravel 5 API authorization for mobile applications which uses Facebook for authorization
我正在研究移动应用程序的后端部分。后端将是 RESTful API。我的主要问题是 authorization/authentication 用户。
我们将在移动应用程序端使用Facebook 授权(Facebook SDK for iOS)。这里的主要问题是:如何仅使用我们从 Facebook 获取的数据在后端实现授权?
也许有人已经找到了一些解决方案或者可以为这个任务提供一些例子?
我可以把这个过程想象成:
用户在应用程序中按下 "Login with FB" 按钮并获得重定向到 FB,在那里他批准连接
用户 returns 使用来自 FB 的一些数据(用户 Facebook ID、一些用户数据和授权令牌)到应用程序
应用程序将此数据发送到 API 并尝试 register/authenticate 用户
API 保存授权令牌,然后在应用程序向 API
发送请求时使用此令牌检查用户
我是对的还是这个逻辑错了?请指教,如果可能的话提供一些例子。
我也找到了 this guy,但不确定它是否对我的情况有帮助...
过程看起来不错。只有一件事你必须添加 - 当你进行 API 调用时确实包括 Laravel CSRF token.
所以,对这个问题做了一些研究,现在有了一些结果。身份验证过程现在如下所示:
在客户端:
- 使用 Facebook API 登录并获取 OAUTH2 代码。
- 将此代码交换为访问令牌。
- 从我的 API 请求访问令牌,包括 Facebook 令牌作为
一个参数
上API
接收访问令牌请求。
使用 facebook 访问权限向 /me Facebook 图发出请求
令牌
验证 Facebook 用户是否存在并与我的用户匹配
数据库
创建我自己的访问令牌,保存它并return它给客户端
从现在开始使用
首先,我为用户 table:
创建了一个迁移
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id')->unique();
$table->bigInteger('facebook_id')->unique();
$table->string('name')->unique();
$table->string('email')->unique();
$table->string('password')->nullable();
$table->string('accessToken')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
然后我将 LaravelFacebookSdk 添加到项目中,该项目是完全经过单元测试的包,可轻松将 Facebook SDK v5 集成到 Laravel 和 Lumen 中。
然后我添加了一些用于身份验证的路由:
Route::group(['prefix' => '/auth' /*, 'middleware' => 'throttle:10,5'*/], function () {
Route::get('/', 'ApiAuthController@index');
Route::get('/base', 'ApiAuthController@baseAuth');
Route::get('/fb', 'ApiAuthController@facebookAuth');
Route::get('/vk', 'ApiAuthController@vkAuth');
});
并创建了一个控制器来处理这些路由:
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use SammyK\LaravelFacebookSdk\LaravelFacebookSdk;
use App\User;
class ApiAuthController extends Controller
{
protected $baseAuthFailedResponse = [
'status' => false,
'message' => 'Base authentication failed'
];
protected $facebookAuthFailedResponse = [
'status' => false,
'message' => 'Facebook authentication failed'
];
protected $vkAuthFailedResponse = [
'status' => false,
'message' => 'VK authentication failed'
];
/**
* Echo function
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request){
return response()->json($request);
}
/**
* Authorise user with base authorisation using email and password
*
* @param Request $request - expects fields: email, password
* @return \Illuminate\Http\JsonResponse
*/
public function baseAuth(Request $request){
$isAuthorised = Auth::attempt(
array(
'email' => $request->input('email'),
'password' => $request->input('password')
)
);
if ($isAuthorised){
return response()->json(Auth::user());
}
return response()->json($this->baseAuthFailedResponse);
}
/**
* Authorise user using facebook accessToken received in the request
*
* @param Request $request - expects fields: accessToken, username, fullName, email
* @return \Illuminate\Http\JsonResponse
*/
public function facebookAuth(Request $request, LaravelFacebookSdk $fb){
if(!Auth::check()){
// Receive access token request.
$accessToken = $request->input('accessToken');
// Make a request to the /me Facebook graph using the facebook access token
try {
$response = $fb->get('/me?fields=id,name,email', $accessToken);
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
$this->facebookAuthFailedResponse['details']['message'] = $e->getMessage();
$this->facebookAuthFailedResponse['details']['error_code'] = $e->getCode();
return response()->json($this->facebookAuthFailedResponse);
}
// Verify that the Facebook user exists and match to a user in my database or create new one
// Convert the response to a `Facebook/GraphNodes/GraphUser` collection
$facebookUser = $response->getGraphUser();
// Create the user if it does not exist or update the existing entry.
// This will only work if you've added the SyncableGraphNodeTrait to your User model.
$user = User::createOrUpdateGraphNode($facebookUser);
Auth::login($user, true);
}
return response()->json(Auth::user());
}
public function vkAuth(Request $request){
return response()->json($this->vkAuthFailedResponse);
}
}
此外,如您所见,我使用了 LaravelFacebookSdk 提供的函数 $user = User::createOrUpdateGraphNode($facebookUser);
。要在我们的模型中使用它,我们应该实现 SyncableGraphNodeTrait
。这种方法确实使得直接从 Facebook returned 获取数据并在本地数据库中创建或更新它变得容易。
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;
class User extends Authenticatable
{
use SyncableGraphNodeTrait;
/**
* The keys of the array are the names of the fields on the Graph node.
* The values of the array are the names of the columns in the local database.
*/
protected static $graph_node_field_aliases = [
'id' => 'facebook_id'
];
/**
* 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', 'remember_token',
];
}
如果有人对解决方案有任何意见,请在评论中提供。
UPD: 我从 this topic. And also this topic was very useful. An API description from the official site. How to easy remember the user I found in this topc. And there I found some useful information about API servers on Laravel. And good description about authentication with tokens
得到的授权过程描述
我正在研究移动应用程序的后端部分。后端将是 RESTful API。我的主要问题是 authorization/authentication 用户。
我们将在移动应用程序端使用Facebook 授权(Facebook SDK for iOS)。这里的主要问题是:如何仅使用我们从 Facebook 获取的数据在后端实现授权?
也许有人已经找到了一些解决方案或者可以为这个任务提供一些例子?
我可以把这个过程想象成:
用户在应用程序中按下 "Login with FB" 按钮并获得重定向到 FB,在那里他批准连接
用户 returns 使用来自 FB 的一些数据(用户 Facebook ID、一些用户数据和授权令牌)到应用程序
应用程序将此数据发送到 API 并尝试 register/authenticate 用户
API 保存授权令牌,然后在应用程序向 API
发送请求时使用此令牌检查用户
我是对的还是这个逻辑错了?请指教,如果可能的话提供一些例子。
我也找到了 this guy,但不确定它是否对我的情况有帮助...
过程看起来不错。只有一件事你必须添加 - 当你进行 API 调用时确实包括 Laravel CSRF token.
所以,对这个问题做了一些研究,现在有了一些结果。身份验证过程现在如下所示:
在客户端:
- 使用 Facebook API 登录并获取 OAUTH2 代码。
- 将此代码交换为访问令牌。
- 从我的 API 请求访问令牌,包括 Facebook 令牌作为 一个参数
上API
接收访问令牌请求。
使用 facebook 访问权限向 /me Facebook 图发出请求 令牌
验证 Facebook 用户是否存在并与我的用户匹配 数据库
创建我自己的访问令牌,保存它并return它给客户端 从现在开始使用
首先,我为用户 table:
创建了一个迁移<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id')->unique();
$table->bigInteger('facebook_id')->unique();
$table->string('name')->unique();
$table->string('email')->unique();
$table->string('password')->nullable();
$table->string('accessToken')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
然后我将 LaravelFacebookSdk 添加到项目中,该项目是完全经过单元测试的包,可轻松将 Facebook SDK v5 集成到 Laravel 和 Lumen 中。
然后我添加了一些用于身份验证的路由:
Route::group(['prefix' => '/auth' /*, 'middleware' => 'throttle:10,5'*/], function () {
Route::get('/', 'ApiAuthController@index');
Route::get('/base', 'ApiAuthController@baseAuth');
Route::get('/fb', 'ApiAuthController@facebookAuth');
Route::get('/vk', 'ApiAuthController@vkAuth');
});
并创建了一个控制器来处理这些路由:
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use SammyK\LaravelFacebookSdk\LaravelFacebookSdk;
use App\User;
class ApiAuthController extends Controller
{
protected $baseAuthFailedResponse = [
'status' => false,
'message' => 'Base authentication failed'
];
protected $facebookAuthFailedResponse = [
'status' => false,
'message' => 'Facebook authentication failed'
];
protected $vkAuthFailedResponse = [
'status' => false,
'message' => 'VK authentication failed'
];
/**
* Echo function
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request){
return response()->json($request);
}
/**
* Authorise user with base authorisation using email and password
*
* @param Request $request - expects fields: email, password
* @return \Illuminate\Http\JsonResponse
*/
public function baseAuth(Request $request){
$isAuthorised = Auth::attempt(
array(
'email' => $request->input('email'),
'password' => $request->input('password')
)
);
if ($isAuthorised){
return response()->json(Auth::user());
}
return response()->json($this->baseAuthFailedResponse);
}
/**
* Authorise user using facebook accessToken received in the request
*
* @param Request $request - expects fields: accessToken, username, fullName, email
* @return \Illuminate\Http\JsonResponse
*/
public function facebookAuth(Request $request, LaravelFacebookSdk $fb){
if(!Auth::check()){
// Receive access token request.
$accessToken = $request->input('accessToken');
// Make a request to the /me Facebook graph using the facebook access token
try {
$response = $fb->get('/me?fields=id,name,email', $accessToken);
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
$this->facebookAuthFailedResponse['details']['message'] = $e->getMessage();
$this->facebookAuthFailedResponse['details']['error_code'] = $e->getCode();
return response()->json($this->facebookAuthFailedResponse);
}
// Verify that the Facebook user exists and match to a user in my database or create new one
// Convert the response to a `Facebook/GraphNodes/GraphUser` collection
$facebookUser = $response->getGraphUser();
// Create the user if it does not exist or update the existing entry.
// This will only work if you've added the SyncableGraphNodeTrait to your User model.
$user = User::createOrUpdateGraphNode($facebookUser);
Auth::login($user, true);
}
return response()->json(Auth::user());
}
public function vkAuth(Request $request){
return response()->json($this->vkAuthFailedResponse);
}
}
此外,如您所见,我使用了 LaravelFacebookSdk 提供的函数 $user = User::createOrUpdateGraphNode($facebookUser);
。要在我们的模型中使用它,我们应该实现 SyncableGraphNodeTrait
。这种方法确实使得直接从 Facebook returned 获取数据并在本地数据库中创建或更新它变得容易。
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;
class User extends Authenticatable
{
use SyncableGraphNodeTrait;
/**
* The keys of the array are the names of the fields on the Graph node.
* The values of the array are the names of the columns in the local database.
*/
protected static $graph_node_field_aliases = [
'id' => 'facebook_id'
];
/**
* 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', 'remember_token',
];
}
如果有人对解决方案有任何意见,请在评论中提供。
UPD: 我从 this topic. And also this topic was very useful. An API description from the official site. How to easy remember the user I found in this topc. And there I found some useful information about API servers on Laravel. And good description about authentication with tokens
得到的授权过程描述