基于API调用的响应的自定义用户身份验证 [英] Custom user authentication base on the response of an API call
问题描述
说明:
我现在一直在使用Laravel进行很多项目.
在Laravel中,实现用户身份验证很简单.现在,我要处理的结构有所不同-我在本地没有database
或users
表.我必须进行API调用以查询所需信息.
I have been using Laravel for a bunch of project now.
Implementing User Authentication is simple in Laravel. Now, the structure that I am dealing with is a little different - I don't have a database
or a users
table locally. I have to make an API call to query what I need.
我已经尝试
public function postSignIn(){
$username = strtolower(Input::get('username'));
$password_api = VSE::user('password',$username); // abc <-----
$password = Input::get('password'); // abc <-----
if ( $password == $password_api ) {
//Log user in
$auth = Auth::attempt(); // Stuck here <----
}
if ($auth) {
return Redirect::to('/dashboard')->with('success', 'Hi '. $username .' ! You have been successfully logged in.');
}
else {
return Redirect::to('/')->with('error', 'Username/Password Wrong')->withInput(Request::except('password'))->with('username', $username);
}
}
已更新
我在VSE
类中使用简单的shell_exec
命令连接到API
I connect to the API using a simple shell_exec
command in my VSE
class
public static function user($attr, $username) {
$data = shell_exec('curl '.env('API_HOST').'vse/accounts');
$raw = json_decode($data,true);
$array = $raw['data'];
return $array[$attr];
}
我希望可以在此向您显示,但是它在本地计算机上的VM上,因此请在这里与我在一起.基本上
I wish I can show that to you here, But it is on the VM on my local machine so please stay with me here. Basically, It
执行
curl http://172.16.67.137:1234/vse/accounts
< ---更新
curl http://172.16.67.137:1234/vse/accounts
<--- updated
响应
Object
data:Array[2]
0:Object
DBA:""
account_id:111
account_type:"admin"
address1:"111 Park Ave"
address2:"Floor 4"
address3:"Suite 4011"
city:"New York"
customer_type:2
display_name:"BobJ"
email_address:"bob@xyzcorp.com"
first_name:"Bob"
last_name:"Jones"
last_updated_utc_in_secs:200200300
middle_names:"X."
name_prefix:"Mr"
name_suffix:"Jr."
nation_code:"USA"
non_person_name:false
password:"abc"
phone1:"212-555-1212"
phone2:""
phone3:""
postal_code:"10022"
state:"NY"
time_zone_offset_from_utc:-5
1:Object
DBA:""
account_id:112
account_type:"mbn"
address1:"112 Park Ave"
address2:"Floor 3"
address3:"Suite 3011"
city:"New York"
customer_type:2
display_name:"TomS"
email_address:"tom@xyzcorp.com"
first_name:"Tom"
last_name:"Smith"
last_updated_utc_in_secs:200200300
middle_names:"Z."
name_prefix:"Mr"
name_suffix:"Sr."
nation_code:"USA"
non_person_name:false
password:"abd"
phone1:"212-555-2323"
phone2:""
phone3:""
postal_code:"10022"
state:"NY"
time_zone_offset_from_utc:-5
message:"Success"
status:200
如您所见,鲍勃(Bob)的密码为abc
,汤姆(Tom)的密码为abd
As you can see the password for Bob is abc
and for Tom is abd
推荐答案
通过执行以下步骤,您可以设置自己的身份验证驱动程序,该驱动程序使用API调用来处理获取和验证用户凭据的操作:
By following the steps below, you can setup your own authentication driver that handles fetching and validating the user credentials using your API call:
1..在app/Auth/ApiUserProvider.php
中使用以下内容创建您自己的自定义用户提供程序:
1. Create your own custom user provider in app/Auth/ApiUserProvider.php
with the following contents:
namespace App\Auth;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
class ApiUserProvider implements UserProvider
{
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
$user = $this->getUserByUsername($credentials['username']);
return $this->getApiUser($user);
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
$user = $this->getUserById($identifier);
return $this->getApiUser($user);
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(UserContract $user, array $credentials)
{
return $user->getAuthPassword() == $credentials['password'];
}
/**
* Get the api user.
*
* @param mixed $user
* @return \App\Auth\ApiUser|null
*/
protected function getApiUser($user)
{
if ($user !== null) {
return new ApiUser($user);
}
}
/**
* Get the use details from your API.
*
* @param string $username
* @return array|null
*/
protected function getUsers()
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, env('API_HOST') . 'vse/accounts');
$response = curl_exec($ch);
$response = json_decode($response, true);
curl_close($ch);
return $response['data'];
}
protected function getUserById($id)
{
$user = [];
foreach ($this->getUsers() as $item) {
if ($item['account_id'] == $id) {
$user = $item;
break;
}
}
return $user ?: null;
}
protected function getUserByUsername($username)
{
$user = [];
foreach ($this->getUsers() as $item) {
if ($item['email_address'] == $username) {
$user = $item;
break;
}
}
return $user ?: null;
}
// The methods below need to be defined because of the Authenticatable contract
// but need no implementation for 'Auth::attempt' to work and can be implemented
// if you need their functionality
public function retrieveByToken($identifier, $token) { }
public function updateRememberToken(UserContract $user, $token) { }
}
2..还要创建一个用户类,该用户类使用以下内容扩展由app/Auth/ApiUser.php
中的身份验证系统提供的默认GenericUser
:
2. Also create a user class that extends the default GenericUser
offered by the authentication system in app/Auth/ApiUser.php
with the following contents:
namespace App\Auth;
use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
class ApiUser extends GenericUser implements UserContract
{
public function getAuthIdentifier()
{
return $this->attributes['account_id'];
}
}
3..在您的app/Providers/AuthServiceProvider.php
文件的引导方法中,注册新的驱动程序用户提供程序:
3. In your app/Providers/AuthServiceProvider.php
file's boot method, register the new driver user provider:
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
// The code below sets up the 'api' driver
$this->app['auth']->extend('api', function() {
return new \App\Auth\ApiUserProvider();
});
}
4..最后,在您的config/auth.php
文件中,将驱动程序设置为自定义驱动程序:
4. Finally in your config/auth.php
file set the driver to your custom one:
'driver' => 'api',
您现在可以在控制器操作中执行以下操作:
You can now do the following in your controller action:
public function postSignIn()
{
$username = strtolower(Input::get('username'));
$password = Input::get('password');
if (Auth::attempt(['username' => $username, 'password' => $password])) {
return Redirect::to('/dashboard')->with('success', 'Hi '. $username .'! You have been successfully logged in.');
} else {
return Redirect::to('/')->with('error', 'Username/Password Wrong')->withInput(Request::except('password'))->with('username', $username);
}
}
成功登录后调用Auth::user()
以获取用户详细信息,将返回一个ApiUser
实例,其中包含从远程API提取的属性,并且看起来像这样:
Calling Auth::user()
to get user details after a successful login, will return an ApiUser
instance containing the attributes fetched from the remote API and would look something like this:
ApiUser {#143 ▼
#attributes: array:10 [▼
"DBA" => ""
"account_id" => 111
"account_type" => "admin"
"display_name" => "BobJ"
"email_address" => "bob@xyzcorp.com"
"first_name" => "Bob"
"last_name" => "Jones"
"password" => "abc"
"message" => "Success"
"status" => 200
]
}
由于您还没有发布用户电子邮件的API中没有匹配项时得到的响应示例,因此我在getUserDetails
方法中设置了条件,以确定没有匹配项并返回data
属性或data
属性为空.您可以根据需要更改该条件.
Since you haven't posted a sample of the response that you get when there's no match in the API for the user email, I setup the condition in the getUserDetails
method, to determine that there's no match and return null
if the response doesn't contain a data
property or if the data
property is empty. You can change that condition according to your needs.
上面的代码是使用模拟的响应进行测试的,该响应返回您在问题中发布的数据结构,并且效果很好.
The code above was tested using a mocked response that returns the data structure you posted in your question and it works very well.
最后一点::您应该强烈考虑修改API,以便尽快而不是稍后(可能使用Oauth实现)来处理用户身份验证,因为密码已经发送了(更令人担忧)作为纯文本)不是您想要推迟的事情.
As a final note: you should strongly consider modifying the API to handle the user authentication sooner rather than later (perhaps using a Oauth implementation), because having the password sent over (and even more worryingly as plain text) is not something you want to postpone doing.
这篇关于基于API调用的响应的自定义用户身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!