使用Laravel进行REST API身份验证

9

我正在使用 Laravel 中的 RESTful 控制器属性构建一个 RESTful API。到目前为止,我已经能够让大部分功能正常工作了。现在遇到的问题是认证,我尝试使用亚马逊的方法,即使用“user_id”和“signature”进行认证。

我使用 PHP 的 'hash_hmac()' 函数创建签名。以下是一个示例 API 控制器:

class Api_Tasks_Controller extends Api_Controller {

    public $restful = true;

    public function get_index($id = null) {

        $this->verfiy_request();

        if(!is_null($id))
        {
            return Response::json(array("tasks"=>"just one"),200);
        }
        else
        {
            return Response::json(array("tasks"=>"everthing"),200);
        }
    }


}

这是API控制器类。
class Api_Controller extends Controller {

    public function verify_request() {

        //user id
        $user_id = (int) Input::get('user_id');
        //signature
        $sig = Input::get('sig');

        //Lookup user
        $user = Sentry::user($user_id);
        if($user) {
            //user email
            $email = $user->email;
            //user api key
            $api_key = $user->metadata['api_key'];
            //recreate signature
            $_sig = hash_hmac("sha256",$email.$user_id,$api_key);
            if($_sig === $sig) {
                return Response::json(array("message"=>"Request Ok"),200);
            }
            else {
                return Response::json(array("message"=>"Request Bad"),400);
            }
        }
        else {

            return Response::json(array("message"=>"Request not authorized"),401);
        }
    }

发起一个GET请求http://api.xyz.com/v1/tasks/1?user_id=1&sig=41295da38eadfa56189b041a022c6ae0fdcbcd5e65c83f0e9aa0e6fbae666cd8总是返回成功的消息,即使我改变了user_id参数的值,这应该会使签名无效并使请求无效。看来我的verfiy_request方法没有执行。请帮帮我。

2个回答

10

我最近也在研究这个问题,建议使用过滤器。可以按照以下方式实现:

class Api_Tasks_Controller extends Base_Controller {

    public $restful = true;

    function __construct() {
        // Check if user is authorized
        $this->filter('before', 'api_checkauth');
    }

    // rest of the class ....

}

在你的routes.php文件中:

Route::filter('api_checkauth', function()
{
  //user id
  $user_id = (int) Input::get('user_id');

  //signature
  $sig = Input::get('sig');

  try {
    //Lookup user
    $user = Sentry::user($user_id);

    if($user) {
      //user email
      $email = $user->email;
      //user api key
      $api_key = $user->metadata['api_key'];
      //recreate signature
      $_sig = hash_hmac("sha256",$email.$user_id,$api_key);
      if($_sig === $sig) {
          return Response::json(array("message"=>"Request Ok"),200);
      }
      else {
          return Response::json(array("message"=>"Request Bad"),400);
      }
    }
    else {
      return Response::json(array("message"=>"Request not authorized"),401);
    }
  }
  catch (Sentry\SentryException $e) {
    $errors = $e->getMessage(); // catch errors such as user not existing or bad fields
    return Response::json(array("message"=>$errors),404);
  }

});

另外,感谢您介绍Sentry给我使用 :-)


你正在请求中发送 $sig 和 $userId。你不觉得任何人都可以嗅探这些参数并代表你进行身份验证吗? - voila
很棒的问题!是的,你对这些元素可以被拦截是正确的。我认为亚马逊使用某种方法在一段时间后使URL过期,出于这个原因。我并不是要挑剔这个人选择的身份验证方式,而是展示如何在Laravel中使用过滤器。 - jonahlyn

2

这只是一个猜测,我没有尝试过,但也许在调用verify_request之前添加一个return语句会有帮助。

您应该了解一下过滤器,这将使您能够更好地分离API逻辑和API身份验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接