Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在每个主干同步请求中发送令牌_Javascript_Api_Backbone.js_Coffeescript - Fatal编程技术网

Javascript 在每个主干同步请求中发送令牌

Javascript 在每个主干同步请求中发送令牌,javascript,api,backbone.js,coffeescript,Javascript,Api,Backbone.js,Coffeescript,我的PHP api要求在我的前端主干应用程序的每个请求中提交一个用户令牌,以确保用户 是活跃的 具有访问资源的权限 在主干网中设置此项的最简单方法是什么?我猜唯一的方法是覆盖Backbone.sync,但是代码会是什么样子呢?咖啡优先 编辑 还有两件事 1.如果出现403:访问禁止错误 2.当应用程序启动时,我从localStorage中提取包含令牌的用户模型 3.我有一个baseModel和baseCollection,所有的模型/集合都来自它 var _sync = Backbone.syn

我的PHP api要求在我的前端主干应用程序的每个请求中提交一个用户令牌,以确保用户

  • 是活跃的
  • 具有访问资源的权限
  • 在主干网中设置此项的最简单方法是什么?我猜唯一的方法是覆盖Backbone.sync,但是代码会是什么样子呢?咖啡优先

    编辑 还有两件事
    1.如果出现
    403:访问禁止错误

    2.当应用程序启动时,我从localStorage中提取包含令牌的用户模型
    3.我有一个baseModel和baseCollection,所有的模型/集合都来自它

    var _sync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
    
        if( model && (method === 'create' || method === 'update' || method === 'patch') ) {
            options.contentType = 'application/json';
            options.data = JSON.stringify(options.attrs || model.toJSON());
        }
    
        _.extend( options.data, {
            "access_token": "some-token"
        });
    
        return _sync.call( this, method, model, options );
    }
    
    只需监听fetch/save方法的失败事件,即可将用户重定向到
    /login

    model.fetch().fail( /* redirect */ )
    
    主干使用jQuery,因此您可以使用“为将来的Ajax请求设置默认值”:

    更新:这个想法的一个改进(感谢@Glen)是每次在请求头中设置令牌之前,都要使用它来检查令牌是否存在:

    $(document).ajaxSend(function(event, request) {
       var token = App.getAuthToken();
       if (token) {
          request.setRequestHeader("token", token);
       }
    });
    

    其中App.getAuthToken()是主干应用程序中的一个函数。

    身份验证是应用程序的责任。

    Backbone.$.ajaxSetup({
       headers: { 'sid': 'blabla' }
    });
    
    对于主干应用程序,身份验证逻辑应该在主干代码中,并且应该不惜一切代价避免更改全局jQuery的
    ajax
    行为。

    ajaxSetup
    ajaxSend
    从上的jQuery文档:

    注意:此处指定的设置将影响对
    $.ajax
    或 基于Ajax的衍生工具,如
    $.get()
    。这可能导致不良后果 由于其他调用方(例如插件)可能期望 正常默认设置。因此,我们强烈建议 反对使用此API。相反,请在中显式设置选项 调用或定义一个简单的插件来执行此操作

    ajaxSend
    与上述问题相同。与
    ajaxSetup
    相比,它唯一的优势是每次调用一个函数,这比传递给
    ajaxSetup
    的基于对象的选项更灵活

    最安全的方法是
    AuthModel
    AuthCollection
    将身份验证逻辑放入基本模型和集合中。这是范围最广的解决方案

    在这里,您可以使用已经存在的
    BaseModel
    ,但我仍然倾向于将
    BaseModel
    AuthModel
    分开,因为您可能希望创建一个自定义模型,该模型使用您的基本模型,但也使用不同的外部API(例如)

    由于模型和集合的新的
    sync
    函数相似,但两者可能有不同的父实现,因此我制作了一个简单的函数生成器

    /**
     * Generates a new sync function which adds the token to the request header 
     * and handles a redirect on error.
     * @param  {Function} syncFn the parent `sync` function to call.
     * @return {Function}  a new version of sync which implements the auth logic.
     */
    var authSyncFunction = function(syncFn) {
        return function(method, model, options) {
            options = options || {};
    
            var beforeSend = options.beforeSend,
                error = options.error;
    
            _.extend(options, {
                // Add auth headers
                beforeSend: function(xhr) {
                    xhr.setRequestHeader('Authorization', "Bearer " + yourTokenHere);
                    if (beforeSend) return beforeSend.apply(this, arguments);
                },
    
                // handle unauthorized error (401)
                error: function(xhr, textStatus, errorThrown) {
                    if (error) error.call(options.context, xhr, textStatus, errorThrown);
                    if (xhr.status === 401) {
                        Backbone.history.navigate('login');
                    }
                }
            });
    
            return syncFn.call(this, method, model, options);
        };
    };
    
    在模型和集合上使用生成器

    var AuthModel = BaseModel.extend({
        sync: authSyncFunction(BaseModel.prototype.sync)
    });
    
    var AuthCollection = BaseCollection.extend({
        sync: authSyncFunction(BaseCollection.prototype.sync)
    });
    
    然后您就可以在模型和集合上使用这些了,您肯定需要进行身份验证。因为您已经在使用基本模型和集合,所以只需将
    BaseModel.extend
    更改为
    AuthModel.extend

    虽然我知道你要求对
    403禁止
    响应进行重定向,但我认为应该对
    401未授权
    进行重定向。看

    覆盖主干的
    sync
    如果此时您不想更改所有模型和集合,但仍然希望遵循良好实践并避免更改全局ajax设置,那么覆盖
    主干.sync
    函数是一个简单的选择

    使用我们先前定义的
    sync
    生成器:

    Backbone.sync = authSyncFunction(Backbone.sync);
    
    管理本地存储和身份验证 要管理本地存储中的数据,请选中

    这是主干模型的一个很好的实现,它与本地存储同步,而不是RESTAPI。它还提供了一个很好的界面来管理身份验证


    服务器需要如何使用访问令牌?在URL中,作为HTTP头,还是在请求正文/JSON中?我在这里回答了一个类似的问题:generic$_REQUEST['token']-看看你的答案,我已经有了$.ajaxPrefilter在基本url上-如果我将token添加为数据参数,这会起作用吗?我不知道
    $_REQUEST['token']
    是什么-一些PHP catchall,包括主体、标题、会话等。我猜是在同一个bucket中?如果是这样,只需将其添加到jQueryAjax设置中的
    headers
    对象中即可。但不确定。谢谢-现在就用这个解决方案解决一个问题-这对POST/UPDATE/CREATE请求不起作用…我该如何解决这个问题?让我问你Simon-有没有更好的方法来验证一个单页主干应用程序,然后在每个请求上发送一个登录令牌?嗯,这是跨域身份验证的一个好方法(至少如果token符合OAuth标准)。但是如果它在同一个域上,会话cookie(或者只是cookie)可能会更容易。嘿,我今天遇到一个讨论,这让我想到了你的问题。也许你可以使用)jQuery文档不建议使用
    $.ajaxSetup
    。请参见此处:另一种选择是使用
    $.ajaxSend
    添加适当的标题。还可以查看OAuth 2.0上的这篇演讲,以及他们如何使用
    $。ajaxSend
    在每个请求中传递令牌:
    $。ajaxSend
    应更改为
    $(文档)。ajaxSend
    根据jQuery 1.9中的
    ,jQuery全局Ajax事件的所有处理程序,包括使用.ajaxSend()方法添加的处理程序,都必须附加到文档中。
    ajaxSend
    ajaxSetup
    ,在这种情况下,应避免使用特定于应用程序的解决方案。
    Backbone.sync = authSyncFunction(Backbone.sync);
    
    // Extend from Session to implement your API's behaviour
    var Account = Session.extend({
      signIn: function () {},
      signOut: function () {},
      getAuthStatus: function () {}
    });
    
    // Using the custom Account implementation
    var session = new Account();
    session.fetch()
      .then(session.getAuthStatus)
      .then(function () {
        console.log('Logged in as %s', session.get('name'));
      })
      .fail(function () {
        console.log('Not yet logged in!');
      });