草庐IT

php - 基于 API 调用响应的自定义用户身份验证

coder 2024-01-03 原文

描述:

我现在已经在很多项目中使用 Laravel。 在 Laravel 中实现用户身份验证很简单。现在,我处理的结构有点不同 - 我在本地没有 databaseusers 表。我必须调用 API 来查询我需要的东西。


我试过了

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

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 上,所以请留在我这里。基本上,它

执行

curl http://172.16.67.137:1234/vse/accounts <--->

响应

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

最佳答案

按照以下步骤,您可以设置自己的身份验证驱动程序,使用您的 API 调用来处理获取和验证用户凭据:

1.app/Auth/ApiUserProvider.php 中使用以下内容创建您自己的自定义用户提供程序:

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以下内容:

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 文件的启动方法中,注册新的驱动程序用户提供程序:

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 文件中将驱动程序设置为您的自定义驱动程序:

    'driver' => 'api',

您现在可以在 Controller 操作中执行以下操作:

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() 以在成功登录后获取用户详细信息,将返回一个包含从远程 API 获取的属性的 ApiUser 实例,看起来像像这样:

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 属性为空,则匹配并返回 null。您可以根据需要更改该条件。


上面的代码使用模拟响应进行了测试,该响应返回您在问题中发布的数据结构并且运行良好。

作为最后的说明:您应该强烈考虑修改 API 以尽早处理用户身份验证(可能使用 Oauth 实现),因为发送密码(更令人担忧的是作为纯文本)不是你想推迟做的事情。

关于php - 基于 API 调用响应的自定义用户身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33331421/

有关php - 基于 API 调用响应的自定义用户身份验证的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  7. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

随机推荐