转载

使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

在开发应用程序时,您可能发现需要让用户将文件存储在服务器上。为了解决这个问题,您可能只是简单地将文件存储在数据库中,甚至可能将它们直接存储在文件系统上。不幸的是,这些传统方法存在一些缺陷。如果直接将文件存储在文件系统上,则需要额外的工作来确保稳定性和安全性,并创建备份。将大型文件存储在数据库中会让性能变得糟糕,备份变得耗时,还原变得缓慢。

一些 Object Storage 服务已开发了出来,它们通过提供高度可用、基于云的存储来减轻这些问题,并为您扩展、保护和维护这些存储。

Bluemix 现在支持通过所谓的 Object Storage 服务来免费访问 Softlayer 的 Object Storage 。Object Storage 服务可通过 Bluemix 服务目录获取,由 OpenStack 的 Swift Object Store 提供支持。您可以在 OpenStack 网站上 阅读该 API 的概述。

Bluemix Object Storage 概述

概念

可通过 Swift 管理 3 种类型的资源:

  • 对象 :文件数据和任何关联的元数据。
  • 容器 :对象的逻辑分组,让所有对象都具有不同的名称。
  • 帐户: 容器分组,使用帐户凭据来保护。帐户由服务提供商在配备时创建。

安全性

在通过 Bluemix 创建 Object Storage 服务的实例时,会为您分配一个帐户,您的所有容器和对象都存储在该帐户下。您帐户的凭据可通过 VCAP_SERVICES 提供。

{   "objectstorage": [{    "name": "instance_basic",    "label": "objectstorage",    "plan": "plan_name",    "credentials": {     "auth_uri": "https://host:port/auth/instance_id/binding_id",     "username": "user_name",     "password": "password"    }    }]   } 

在创建任何对象或从服务读取任何对象之前,您必须从服务器获取一个授权令牌。该令牌使用包含上述凭据的基本身份验证机制从 auth_uri 端点获取。然后,获取的令牌可用在处理容器和对象的所有后续请求上。

您还能够在容器上创建访问控制列表 (ACL) 来增加对其他对象存储帐户访问限制和其他访问条件。尽管可使用 ACL 在帐户之间共享数据,但应该认识到这些帐户是特定于项目,而不是特定于最终用户。

此身份验证模式具有两大挑战:

  1. 您如何允许用户访问存储在您服务器上的文件,同时不会向客户端公开您的帐户凭据?
  2. 如果所有文件都存储在同一个帐户下,您如何预防用户 A 访问用户 B 的文件?

每种挑战都可通过以下方式克服:

  1. 使用一个服务器端代理来防止将帐户凭据暴露给客户端
  2. 保护代理并使用 Bluemix Single Sign On (SSO) 来验证用户

本文通过一个应用程序展示如何解决这些限制。

应用程序

该应用程序是一个基于 Web 的简单的镜像管理应用程序。用户通过 LinkedIn 执行身份验证,能够上传新镜像,还能够查看、更新和删除已存储的镜像。

运行应用程序

获取代码

第 1 步. 在 Bluemix 上创建一个节点应用程序

  1. 登录到 Bluemix 。
  2. 单击仪表板中的 Create an Application 。
  3. 在要求指定创建的应用程序类型时,单击 Web 。
  4. 选择 SDK for Node.js 选项并单击 Continue 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制
  5. 命名您的应用程序。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

第 2 步. 配备 Object Storage 服务

  1. 单击顶部菜单栏中的 Catalog 。
  2. 从左侧选择 Data Management 类别。
  3. 选择 Object Storage 。
  4. 选择第 1 步中创建的 App ,如果您愿意的话,还可以更新 Service name 。单击 Create 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

    点击查看大图

    关闭 [x]

    使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

  5. 在创建实例后,系统会提示您重新启动您的应用程序。单击 Restage 。

第 3 步. 测试 Object Storage 服务身份验证

如果已理解 Object Storage 服务如何验证用户,可跳过这一步。 Object Storage 文档页面 上也介绍了这一步。

  1. 要测试验证,需要一个 REST 客户端,比如 cURL 或 Chrome 插件 Postman 。
  2. 从您应用程序的 VCAP_Services 复制 auth_uri、username 和 password。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

    点击查看大图

    关闭 [x]

    使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

  3. 要获取令牌,必须通过基本身份验证向 https://auth_uri/username 执行一次 GET 请求。包含上述凭据的 cURL 命令类似于:

    点击查看代码清单

    关闭 [x]

    curl -i --user da938ab5c18601a38c45b3ad6c97cb8d1e7441da:29b6eb028cfdd3e1fec0cc8fa2066fea4a169cb352819e3dfa11e3f0efde https://swift.ng.bluemix.net/auth/45947227-d694-4e3b-beb4-66bfe895752d/bf587adc-10b8-40d8-aeb5-805f73f13844/da938ab5c18601a38c45b3ad6c97cb8d1e7441da
  4. 服务器响应包含 X-Storage-URL 和 X-Auth-Token 标头(表示您的对象存储所在的 URL)和您必须包含在所有请求上的授权令牌。

    点击查看代码清单

    关闭 [x]

    HTTP/1.1 200 OK   X-Backside-Transport: OK OK   Connection: Keep-Alive   Transfer-Encoding: chunked   Content-Type: application/json:charset=utf-8   Date: Fri, 30 Jan 2015 18:33:12 GMT   Set-Cookie: connect.sid=s%3AnPo52qjvdynxlvCGEAmJfs7d.HuYPqYVmtQqeImm73iUnubk2r9T0S5WIQVOL5edX08U; Path=/; HttpOnly   --> X-Auth-Token: AUTH_tk924cd97c2af7475c8e6cb25d2adaccf8   X-Cf-Requestid: 969d6f00-8b85-471e-5ab5-80c36031f9fb   X-Powered-By: Express   --> X-Storage-Url: https://dal05.objectstorage.softlayer.net/v1/AUTH_0c6bf5d5-b5e4-43aa-93f1-ea7065837fb8   X-Client-IP: 129.42.208.182   X-Global-Transaction-ID: 770597619
  5. 所有后续请求都将在 X-Storage-Url 标头中提供的 URL 上,而且必须包含 X-Auth-Token 标头。例如,要为您的存储创建一个新容器,可以发出以下请求:

    点击查看代码清单

    关闭 [x]

    curl -i -H "X-Auth-Token: AUTH_tk924cd97c2af7475c8e6cb25d2adaccf8" -X PUT https://dal05.objectstorage.softlayer.net/v1/AUTH_0c6bf5d5-b5e4-43aa-93f1-ea7065837fb8/myNewContiner

如果一切运行正常,您会从服务器收到 201 响应代码。您可以在同一个 URL 上使用已设置的 X-Auth-Token 标头执行一次 GET 命令,获取与您的帐户有关联的所有容器:

点击查看代码清单

关闭 [x]

curl -i -H "X-Auth-Token: AUTH_tk924cd97c2af7475c8e6cb25d2adaccf8" https://dal05.objectstorage.softlayer.net/v1/AUTH_0c6bf5d5-b5e4-43aa-93f1-ea7065837fb8/

服务器响应应类似于以下内容,其中包含您创建的一个容器列表:

HTTP/1.1 200 OK  Content-Length: 44  Content-Type: text/plain; charset=utf-8  X-Account-Object-Count: 0  X-Timestamp: 1422642699.36706  X-Account-Meta-Cdn-Id: 21904  X-Account-Bytes-Used: 0  X-Account-Container-Count: 3  X-Account-Meta-Nas-Id: 4359794  Accept-Ranges: bytes  X-Trans-Id: tx0284889f9e2b47dca6c39-0054cbea86  Date: Fri, 30 Jan 2015 20:33:10 GMT    myNewContiner  myNewContiner2  myNewContiner3

第 4 步. 配备 Single Sign On 服务

  1. 单击顶部菜单栏中的 Catalog 。
  2. 从左侧选择 Security 。
  3. 选择 Single Sign On 。
  4. 将 App 更改为 Leave Unbound ,如果需要的话,还可以更改 Service name 。
  5. 单击 Create 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

    点击查看大图

    关闭 [x]

    使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

    备注:您将在第 6 步绑定该服务。

第 5 步. 为 LinkedIn 配置 Single Sign On 服务

配备 Single Sign On 服务后,您的信息将发送到服务控制台。也可以从仪表板中的服务部分中打开此控制台。

  1. 第一次打开 SSO 控制台时,您会看到一个欢迎窗口,它要求您为服务提供一个名称。提供一个名称,然后单击 Continue 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

    备注:单击 Continue 后,可能需要花一分钟来配备服务,在此期间控制台将会无响应。

  2. 我们希望让用户使用 LinkedIn 执行验证,所以在左侧选择 LinkedIn 。
  3. 在 Configure your Identity Source 面板中,按照说明在 LinkedIn 上注册您的应用程序。在 LinkedIn 上注册您的应用程序后,确保使用了 Configure your Identity Source 所提供的 OAuth 2.0 Redirect URL 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制
  4. 单击 Agree (阅读 API 使用条款后)和 Add Application 。
  5. LinkedIn 将为您提供 OAuth 密钥。将 API Key 和 API Secret 复制到 SSO Console 中的 Step 2 下的相应字段,然后单击 Save 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制

第 6 步. 集成 SSO 服务与您的应用程序

  1. 选择第 1 步中创建的 NodeJS 应用程序,然后单击 Bind a Service 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制
  2. 从打开的窗口中选择您刚创建的 SSO 服务,单击 Add 。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制
  3. 出现 Restage Application 应用程序时单击 Restage 。
  4. 从应用程序上下文中打开 SSO 服务控制台。这很重要,因为 Integrate 部分仅在从应用程序的页面打开控制台时可用。 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制 使用 Single Sign On 服务对 Bluemix Object Storage 服务执行细粒度访问控制
  5. 单击右上侧的 Integrate 选项卡。
  6. Return-to URL

    是 SSO 服务器在完成身份验证后将响应的 URL。在本地测试应用程序时,可以使用:http://localhost:3000/sso/redirect。托管在 Bluemix 上时,该 URL 必须更新为:https://<your-app-domain>.mybluemix.net/sso/redirect。

    请注意协议上的区别。对于本地托管的应用程序,使用的协议为 http,但对于 Bluemix 托管的应用程序,则应使用安全 HTTP,也就是 https。

    至于现在,使用 http://localhost:3000/sso/redirect URL 并单击 Save 。

第 7 步. 下载并运行应用程序

  1. 从 JazzHub 下载或克隆应用程序源代码。
  2. 要在本地运行,必须从应用程序复制完整的 VCAP_SERVICES 内容,并将这些内容粘贴到 config.json 文件中。
  3. 打开一个终端并导航到应用程序的目录。
  4. 运行 npm install 。
  5. 要运行应用程序,可从终端运行 node app.js 。
  6. 在浏览器中打开 http://localhost:3000。您会被重定向到 LinkedIn 登录页面。使用您的凭据登录。
  7. 单击右上角的 ‘+’ 符号来测试您能否上传镜像。

第 8 步. 将应用程序部署到 Bluemix

测试所有功能都能在本地运行后,您可以将应用程序部署到 Bluemix 上:

  1. 将 Return-to URL 更新为 https://<your-app-domain>.mybluemix.net/sso/redirect。
  2. 从终端运行 cf push <Your App Name> -p . ,以便将应用程序部署到 Bluemix
  3. 转到 https://<your-app-domain>.mybluemix.net 来测试应用程序

应用程序概述

文件

在解压项目时,您会看到以下文件:

  • app.js:Node 服务器的源代码。
  • config.json:必须使用 SSO 和 Object Storage 服务提供的凭据来更新的配置文件。
  • ./node_modules/:解压之后的 node_modules 目录仅包含 passport-idaas-openidconnet 模块,因为 npm 注册表中还没有这个模块。其他所有模块包都在运行 npm install 时获取。
  • package.json:包含对所有 Node 依赖项的引用。
  • README:项目自述文件。
  • ./web/:包含应用程序的静态内容:index.html 和 modal_dialog.css。

交互

客户端部分是一个使用 AngularJS(一种基于 JavaScript 的框架)编写的单页 Web 应用程序。服务器是使用 NodeJS 编写的,它提供了 REST API,使用 SSO 服务处理授权流,代表客户端向 Object Storage 服务发出请求,还提供了 Web 应用程序的静态内容(HTML、CSS 和 JavaScript)。来自客户端的通信通过 Ajax 请求传输到服务器。

服务器

服务器有两个主要的用途:

  1. 验证和代理发送给 Object Storage 服务的请求
  2. 集成 Single Sign On 服务,以便基于用户身份验证来提供安全保护

服务器是使用 NodeJS 编写的。以下库是我们用来完成此任务的主要的库:

  • ExpressJS:提供 REST API 的标准节点库
  • http-proxy:处理发送给 Object Storage 服务的代理请求
  • passport:处理 OAuth 流
  • passport-idaas-openid:一种将验证请求定向到 Bluemix 的 SSO 服务的护照身份验证战略

服务器有 3 个主要的根端点:

  • /web:提供托管在 /web 下的静态内容
  • /swift:代理对 Object Storage 服务的请求
  • /sso:处理对 Single Sign On 的授权请求

下一节将分析代码。

代理代码

首先,我们在 /swift 路由上创建一个 express 路由器:

如果不熟悉 express 路由器,可以在 Express 文档页面 上查阅有关的更多信息。

var proxyRouter = express.Router();  app.use('/swift', proxyRouter);  proxyRouter.use('/:container', validateProxyRequest);

发送给 https://<app-domain>.mybluemix.net/swift 的所有请求都被转发给对象缓存存储。这通过两个步骤来完成:

  1. 身份验证验证令牌的获取已在上面的 “第 3 步. 测试 Object Storage 服务身份验证” 中演示。下面这个中间件演示了这一过程:
    proxyRouter.use(function (req, res, next) {  var swiftStorageCredentials = cache.get('swiftStorageCredentials')  if(!swiftStorageCredentials === undefined){   var parsedUrl = url.parse(swiftConfig.credentials.auth_uri);   var options = {    hostname: parsedUrl.hostname,    path: parsedUrl.path + '/' + swiftConfig.credentials.username,    method: 'GET',    auth: swiftConfig.credentials.username + ':' + swiftConfig.credentials.password   };   var swiftRequest = https.request(options, function(swiftResponse) {    var storageURL = swiftResponse.headers["x-storage-url"];    var storageToken = swiftResponse.headers["x-auth-token"];    swiftStorageCredentials = new SwiftStorageCredentials(storageURL, storageToken)    cache.set('swiftStorageCredentials', swiftStorageCredentials ) ;    next();   });   swiftRequest.end();  } else{   next();  } }); 

    此中间件首先检查 URL 缓存,查看我们是否已在最近 15 分钟内获得了该令牌。如果没有,则会使用基本的 auth 令牌向授权端点发出一个安全请求。您可以在 swiftRequest 响应回调中看到,我们获得了存储 URL 和 auth 令牌,因此我们可以在后续代理请求中使用它们,并将它们存储在缓存中。

  2. 使用缓存中存储的凭据来发出代理请求。

    为此,我们定义了将请求重定向到代理的中间件:

    proxyRouter.use(function (clientRequest, clientResponse, next){  //Obtain Object Storage service endpoint from stored credentials.  //This will be the target of the proxy.  var swiftStorageCredentials = cache.get('swiftStorageCredentials');  var proxyURL = swiftStorageCredentials.storageURL ;  var options = {target : proxyURL};  if(!clientRequest.header('expect')){   proxy.web(clientRequest, clientResponse, options);  } else{   clientResponse.writeContinue();   clientResponse.setHeader("SkipProxyWeb", "true");   clientResponse.end();  } }); 

    这会获取我们存储在缓存中的存储 URL,并使用指定的同一个路径来调用该代理。换句话说,对 http://hostname/swift/mycontainer/myimage.jpg 的请求被转发到 https://storageURL/mycontainer/myimage.jpg。

    在代理自身上,我们必须定义一个函数,以便所有传出的请求都包含 auth 令牌,该令牌是在我们的第一个中间件所发出的身份验证请求中获取的。

    proxy.on('proxyReq', function(proxiedReq, req, res, options) {     var swiftStorageCredentials = cache.get('swiftStorageCredentials');     if(!req.header(‘expect')){         proxiedReq.setHeader(‘X-Auth-Token', swiftStorageCredentials.storageToken);     } else{         res.setHeader("ProxyRequestEventFoundExpect", "true");     } });

    有了此信息后,向 https://<app-domain>.mybluemix.net/swift 发出的所有请求都会被重定向到对象存储服务,使用帐户凭据来授权请求,而不会向客户端把暴露凭据。

使用 Passport.js 集成 SSO

Single Sign On 文档的 配置 Node.js 应用程序 一节详细介绍了如何使用 Passport.js 节点库和 Single Sign On(passport-idaas-openidconnect) 将第三方用户安全集成到应用程序中。在这一节中,我们将介绍应用程序中的相关更改。

要持久保存用户信息,必须向 express 应用程序注册 express-session 和 cookieParser 中间件。

app.use(cookieParser());  app.use(session({ secret: 'SOME SECRET HERE', resave: true, saveUninitialized: true }));  app.use(passport.initialize());  app.use(passport.session());   //Serializes the user into the session  passport.serializeUser(function(user, done) { done(null, user); });  //Deserializes the user into an object and makes it available on req.user  passport.deserializeUser(function(obj, done) { done(null, obj); });

上述代码初始化并注册了 session 和 passport 中间件。 serializeUser 和 deserializeUser 方法调用描述了如何序列化和去序列化会话中的用户信息。参见 Passport 配置文档 中的 “会话” 部分,了解有关的更多信息。

接下来,我们将设置 Single Sign On 文档中所介绍的 Passport(护照)战略。

//Retrieve SSO credentials from VCAP_SERVICES when running on Bluemix, //or config.json when running locally var services  = isBluemix() ? JSON.parse(process.env.VCAP_SERVICES) : config.VCAP_SERVICES,  ssoConfig = services.SingleSignOn[0]; //Create Passport Strategy with SSO credentials to handle authentication flows passport.use(new OpenIDConnectStrategy({  authorizationURL: ssoConfig.credentials.authorizationEndpointUrl,  tokenURL: ssoConfig.credentials.tokenEndpointUrl,  clientID: ssoConfig.credentials.clientId,  scope: 'openid',  response_type: 'code',  clientSecret: ssoConfig.credentials.secret,  callbackURL: "/sso/redirect",  skipUserProfile: true,  issuer: ssoConfig.credentials.issuerIdentifier }, function(accessToken, refreshToken, profile, done) {  process.nextTick(function() {   profile.accessToken = accessToken;   profile.refreshToken = refreshToken;   done(null, profile);  }) })); 

来自 VCAP_SERVICES 的 SSO 凭据用于实例化 OpenIDConnectStrategy 。此战略会告诉护照,我们希望发出何种授权请求和在何处发出这些请求(使用 SSO 服务)。 authorizationURL 、 tokenURL 、 clientId 、 clientSecret 和 issuer 身份都由 SSO 服务提供。我们还在这里指定,我们希望在完成登录操作后调用我们的 /sso/redirect 端点。

为了简化登录请求,我们创建了一个 authRouter ,并将它与发送给 /sso/* 的所有请求相关联。

var authRouter = express.Router();  app.use('/sso', authRouter);

然后,为了处理登录请求,我们创建了一个 /sso/login 端点,并让护照来处理该请求。

authRouter.get('/login', passport.authenticate('openidconnect', {}));

护照和 SSO 服务将为我们处理实际的身份验证流。完成身份验证后,用户会被重定向到之前提到的 /sso/redirect。

authRouter.get('/redirect',function(req,res,next) {   passport.authenticate('openidconnect',{    successRedirect: "/web",    failureRedirect: '/sso/failure'   })(req,res,next);  });

您可以看到,这个端点表明成功的身份验证将重定向个到 /web/ 端点,用户将能够在其中查看实际的网站。失败的身份验证将被重定向到 '/sso/failure' ,这会通知用户登录失败:

authRouter.get('/failure', function(req, res) { res.send('login failed'); });

要保护端点,必须检查用户是否已在所有请求上进行了验证。为此,我们可以检查 req.isAuthenicated() 是否为 true,也可以检查 req.user 是否允许用户访问请求的容器。

为了保护根 (/) 端点,我们创建了 ensureAuthenticated 函数:

function ensureAuthenticated(req, res, next) {   //If user isn't authenticated, redirect to login   if (!req.isAuthenticated()) {    res.redirect('/sso/login');   } else {    //If authenticated, continue to next middleware     return next();   }  }

它的使用方式是:

app.get('/', ensureAuthenticated, function(req,res,next){   res.redirect('/web');  });

借助代理请求,我们执行一个额外的步骤,确保经过验证的用户仅对允许他们访问的容器发出代理请求。在我们的案例中,我们要求用户 ID(他们的电子邮件地址)与容器的名称匹配。为此,我们创建下面这个函数:

点击查看代码清单

关闭 [x]

function validateProxyRequest(req, res, next) {   if (!req.user) {    console.log("Invalid proxy request. User is not logged in.");    res.send(401).send("Not logged in.");   } else if (req.user.id != req.params.container) {    res.send(401).send("Container and user id don't match. Container: %s, User id: %s”, req.params.container, req.user.id);   } else {    return next();   }  }

在代理端点之前向 proxyRouter 注册,将它注册为中间件。

proxyRouter.use('/:container', validateProxyRequest);

对于 validateProxyRequest 函数,有两点需要注意:

  • 我们检查了 req.user ,而不是 req.isAuthenticated() 。因此我们可确保 req.user.id 与 :container 端点参数 ( req.params.container ) 相匹配。这可以确保用户无法访问其他用户的文件。
  • 我们没有像 ensureAuthenticated 中那样执行重定向,我们发送了 401。这是因为代理请求将使用 Ajax 代理来处理,因此服务器端重定向无法正确处理。如果我们发送 401,我们可登录到存在错误的客户端,通知用户他们需要登录(为了简便起见,我们在应用程序中执行了客户端重定向)。

客户端代码

客户端部分通过流行的 Angular 库 来使用 HTML、CSS 和 JavaScript 编写。Angular 是一个基于 MVC 的框架,用于编写基于 JavaScript 的 Web 应用程序。可以从 Angular 的 在线文档 获取它的概念性概述。出于本文的目的,我们坚持只介绍用于与我们刚演示的服务器通信的控制器的内容。

/web/index.html 中的控制逻辑包含在 HTML 后的脚本标记中。首先,我们定义了一个名为 swiftResourceApp 的模块,它充当着所有 Web 应用程序的逻辑的容器模块。随后,我们定义了 swiftListController ,而且它位于应用程序的大部分逻辑所在的控制器中。

您会注意到,此控制器中定义了多个方法。以下方法用于与服务器通信:

  • getContainer :此方法调用我们在应用程序中定义的一个特殊端点(简言之,就是 /container),该端点将告诉我们此用户有权访问的容器名称。容器名称应与从 Passport 的已验证用户获取的用户 ID 或电子邮件地址相同。 备注: 这不是代理端点。所有其他 Ajax 调用都是对代理发出的。
  • listResources :在 /swift/<container name> 上执行一次 GET ,获取用户的容器中存储的所有文件。如果这是用户第一次登录,服务器会使用一个 404 页面作为响应。此问题的处理方式是,在 /swift/<container name> 上执行一次 PUT ,创建一个具有相同名称的新容器。
  • createResource :在 /swift/<container name>/<resource name> 上使用在请求中作为数据上传的文件的内容执行一次 PUT 。
  • onSaveUpdate :类似于 createResource ,但更新了现有资源。

您会注意到,在对我们的服务器的每次调用中,如果服务器使用 401 作为响应,我们会通过将 window.location.href 更改为登录端点来执行一次客户端重定向:

error(function(response, status){     if (status == 401) {         window.location.href = window.location.origin+"/sso/login";     } else {         console.error("Error updating resource. Error code: %s, Error message: %s", status, response);     } });

结束语

IBM Bluemix 是一个创建和部署以云为中心的应用程序的重要平台。在本文中,我们演示了开发人员如何使用与 Node.js 和 Angular.js 相关的前沿技术(都受 OAUTH 保护),安全地将资源存储在 IBM SoftLayer 的 Object Storage 服务中。通过设计一种多层架构,我们可确保开发人员能够使用 IBM Bluemix 平台开发一个高度可扩展、可靠、高性能的解决方案。Bluemix 上的服务目录非常庞大,而且提供了许多不同的功能,它们对开发人员很有吸引力,可以缩短新一代应用程序的上市准备时间。

BLUEMIX SERVICES USED IN THIS TUTORIAL:

  • Single Sign On 服务 可以帮助您保护为云开发的 Web 和移动应用程序,并轻松地构建和增强应用程序以包含基于策略的用户访问安全。
  • Object Storage 服务 拥有对配置独立对象存储的内置支持,而且它为每个对象存储创建了单独的子帐户。
正文到此结束
Loading...