在backbone.js应用程序中管理身份验证(会话)和授权的最佳设计/体系结构实践是什么?

Pra*_*hra 9 authentication authorization backbone.js

我无论如何都找不到这个.大多数示例应用程序都不讨论安全性等.假设用户将使用基于休息的API调用进行身份验证.如何构建应用程序以处理身份验证[也授权].指向示例应用程序的指针会很棒.请在单页面应用程序和正常应用程序方面添加视图.[我相信每个观点都应该照顾它]

Joh*_*sch 8

你绝对正确,大多数样本根本不解决安全问题.因此,我没有一个很好的样本,我可以指向你.我只能告诉你我们如何构建自己的东西:

  1. 与您的建议一样,我们进行API调用以验证用户身份.在我们的例子中,一旦用户点击第一页(甚至在登录之前)并且存储在cookie客户端侧,就会有Java服务器创建的会话ID.由于该cookie随着向服务器发送的每个HTTPS请求(即使是AJAX调用以获取数据或执行命令)一起运行,因此一旦用户进行了身份验证,它就会与特定的帐户服务器端相关联.

  2. 假设您到服务器的传输是HTTPS并且cookie永远不会通过开放的Internet传播,没有人可以窃听该值并伪装成登录用户.

  3. 在我们的例子中,服务器是基于Java的,并且servlet过滤器位于所有不可公开访问的API函数之前(即需要登录的API函数).它会检查会话并确保它在将请求传递给服务之前表示已登录的用户,并使服务代码保持清除身份验证检查.然而,授权代码和参数验证当前位于服务层中.

  4. 由于各种原因(会话已过期,服务器必须重新启动并且忘记了用户的会话,管理员强制注销用户,因此对API的AJAX调用可能无法进行身份验证)等等.).在我们看来,重要的是服务器仍然返回一些东西(也就是说,不是空的响应),它不应该像重定向到登录页面(这对AJAX请求没用).因此,我们始终从所有函数返回JSend协议响应,如果用户未登录,则servlet过滤器返回带有特定代码的标准JSend"错误"响应.这使我们能够将客户端代码(您可以将其放入自定义同步中)通知用户未登录并提示登录.甚至可以在登录后自动重试该功能,但这比我们的功能更复杂.

  5. 通过让Sync通知用户未登录或遭到安全违规,您不必在视图中添加任何特殊内容.他们只是提出他们认为合适的任何要求,要么成功要么不成功.如果需要重新登录,则会在较低级别触发.

  6. 只要服务器将给定的会话标记为不再登录或丢弃会话记录,则注销实际上并不要求您终止本地cookie.

我对Derick声明客户不应该了解安全性的说法有点不同意.我认为它需要知道何时提示登录,如何告诉服务器何时执行注销,我总是认为在客户端进行额外检查以避免出现意外原则是个好主意.例如,如果我不能使用它们而不是允许我尝试调用它们然后在响应中得到错误,我希望客户端禁止向我显示管理功能.

最终服务器绝对必须再次检查用户的权限与每个请求(因为它很容易回避客户端安全),但良好的UX要求客户端知道我不是管理员,所以它可以呈现最佳的代表性用户界面.


Ant*_*hua 5

几个月前,在使用基于REST的API的单页应用程序中遇到了同样的问题.我在搜索答案后想出的是使用HTTP现有的401和403错误.我有我的api返回这些错误.然后通过使用扩展错误处理模型来处理这些错误并通过路由器导航功能将它们路由到我的登录,从而捕获了异常.

var ErrorHandlerModel = Backbone.Model.extend({

    initialize: function(attributes, options) {
        options || (options = {});
        this.on("error", this.errorHandler);
        this.init && this.init(attributes, options);
    },

    errorHandler: function(model, error) {
        if (error.status == 401 || error.status == 403) {
          app.history.navigate('login', true);
        }
    }

});
Run Code Online (Sandbox Code Playgroud)

事后看来,虽然我认为最好只使用全局jquery ajaxError函数.上面的代码段基于几个月前发布的类似问题.

我还必须覆盖主干的默认提取行为,因此我可以使用ogin触发错误来捕获api的json响应中包含的响应变量.

var Login = Backbone.Model.extend({  

    urlRoot: '/login',

    parse: function(resp,xhr) {
        if (resp.response == 'success') {
            app.history.navigate('dashboard', true);
        }
        else {
            this.trigger('loginError');     
        }
    return false;
    }
});
Run Code Online (Sandbox Code Playgroud)