内容


使用 Redis 和 Bluemix 上的 IBM Single Sign On 服务扩展身份验证

Comments

成功的云级别应用程序设计需要计划如何正确地在应用程序组件和服务中实现横向扩展。在本教程中,您将在 Bluemix 中创建一个使用 IBM Single Sign On 服务的简单 Node.js 应用程序。您会看到将应用程序扩展到单个实例外,并尝试执行身份验证时会发生什么(提示:不会一切顺利)。然后,我将解释哪里出错了,并指导您借助 Bluemix 中的 Redis Cloud 服务,通过一种实现方法来解决问题。

要实现最佳的扩展,每个流程都应设计为无状态的,而且应该始终将数据持久保存到可供所有流程使用的备份服务中。

完成本教程所需的准备工作

  • 一个 Bluemix 帐户
  • 一个安装了以下软件的工作站:
    • Git(用于克隆基础应用程序存储库)
    • Cloud Foundry 命令行接口 6.5 或更高版本
    • 一个文本编辑器,用于对所提供的源代码执行次要更新

运行应用程序获取代码

运行我的演示应用程序时,请使用用户名 clouduser 和密码 Bluemix123 进行登录。

第 1 步. 设置初始应用程序

您的第一个任务是在 Bluemix 中创建一个使用 IBM Single Sign On 服务的简单 Node.js 应用程序。您将创建一个新应用程序,添加并配置一个 Single Sign On 服务实例,将该服务绑定到该应用程序,然后指定回调 URL。

  1. 登录 Bluemix,单击 CREATE APP,然后选择 WEB 作为应用程序类型。
  2. 单击 SDK for Node.js,然后单击 CONTINUE
  3. 为您的应用程序指定一个唯一的名称。例如,您可以使用 scaleSSO 作为名称的开头,后跟一个连字符,然后为了让名称保持唯一,请添加您的姓名首字母和日期,例如 scaleSSO-TOR0815Screenshot of app name example using scaleSSO-TOR0815
    Screenshot of app name example using scaleSSO-TOR0815

    在本教程的剩余部分中,请将 <your app name> 替换为您在此处输入的名称。
  4. 单击 FINISH。等待 Bluemix 暂存和运行您的应用程序。
  5. 单击 VIEW APP OVERVIEW(位于页面底部)。
  6. 在应用程序概述页上,单击 STOP 按钮并确认。您需要向应用程序添加一些代码,然后它才能对 Single Sign On 服务发挥作用。
  7. 转到 Bluemix 目录并单击 Security 服务部分中的 Single Sign OnScreenshot of the Single Sign On service tile in the Bluemix catalog
    Screenshot of the Single Sign On service tile in the Bluemix catalog
  8. App 下拉列表中选择 Leave unbound 并单击 CREATE。等待创建该服务,以及该服务的配置管理器启动。
  9. 键入 scaleSSOtest 作为服务名称并单击 ContinueScreenshot of providing scaleSSOtest as the name for the service
    Screenshot of providing scaleSSOtest as the name for the service
  10. 在提示输入新身份来源的页面上,单击 Cloud Directory 添加一个简单的身份来源。
  11. 单击加号图标添加一个新用户。
  12. Add User 对话框中,输入您选择的用户名和密码,以及其他描述属性。 单击 Save 添加该用户,然后单击 Save 关闭身份来源编辑面板: Screenshot of the UI for adding a user
    Screenshot of the UI for adding a user
  13. 单击 Back to Dashboard 并单击您的应用程序,打开它的概述页。
  14. 在应用程序概述中,单击 BIND A SERVICE OR API
  15. 选择您刚创建的 Single Sign On 服务的单选按钮,然后单击 ADDScreenshot of selecting the Single Sign On service and clicking the ADD button
    Screenshot of selecting the Single Sign On service and clicking the ADD button
  16. 单击 Back to Dashboard 链接右侧的 V 形图标,然后单击下拉菜单中的 Single Sign On 服务: Screenshot of menu  navigation showing application and services and selecting Single Sign On
    再次单击该 V 形图标来关闭下拉菜单。
  17. 单击 Single Sign On 配置管理器右上角的 INTEGRATE 按钮。
  18. Return-to URL 字段中,输入:

    https://<your app name>.mybluemix.net/auth/sso/callback

  19. 单击 Save 按钮,然后单击 OK
  20. 单击 Back to Dashboard

您的初始应用程序设置工作已完成。

第 2 步. 修改应用程序代码并重新部署

在这一步中,您要克隆一个 IBM DevOps Services 项目,该项目包含一个简单的 Node.js 应用程序,已配置为使用 Single Sign On。修改此代码,将它用于您的现有应用程序,然后将代码推送到 Bluemix 来部署该应用程序。

  1. 在您的本地工作站上打开一个命令提示符,然后运行此命令:

    git clone https://hub.jazz.net/git/timro/scaleSSO-base <your app name>

  2. 使用文本编辑器更新 git clone 所创建的新目录中的 app.js 文件。在文件的第 49 行代码中更改 callback_url,使其与您在第 1 步(第 18 小步)中使用的 Return-to URL 值相匹配:
    // you MUST change the host route to match your application name
    var callback_url = 'https://<your app name>.mybluemix.net/auth/sso/callback';
  3. 更新 manifest.yml 文件,替换应用程序的 hostname 属性:
    applications:
    - disk_quota:1024M
      host:<your app name>
      name:<your app name>
      path:.
      domain: mybluemix.net
  4. 将命令行工作目录更改为项目目录,使用 Cloud Foundry 命令行工具登录 Bluemix:

    cf login -a https://api.ng.bluemix.net

  5. 运行以下命令,更新您的应用程序并将其部署到 Bluemix 中:

    cf push

  6. 查看来自 cf push 命令的暂存消息。 部署后,该应用程序将启动,您会看到应用程序实例的状态为 runningScreenshot of the cf command output showing app start and instance details
    Screenshot of the cf command output showing app start and instance details

现在可以测试该应用程序了。

第 3 步. 在 Bluemix 中扩展应用程序

在这一步中,您要测试应用程序的身份验证 — 首先使用单个应用程序实例,然后添加第二个实例。

  1. 在新浏览器窗口或选项卡中,打开应用程序的 URL: https://<your app name>.mybluemix.net.单击 Login 按钮。
  2. 输入您在配置 Single Sign On 服务时添加到 Cloud Directory 的用户名和密码,并单击 Login。如果提示您将初始密码更改为新密码,请执行该操作: Screenshot of the dialog box in Single Sign On service to prompt for changing user's initial password
    Screenshot of the dialog box in Single Sign On service to prompt for changing user's initial password

    您会看到一条问候消息,其中包括已验证的用户名和验证范围 — 例如 揌ello, scalessotest-nw2nz9occb-ck11.iam.ibmcloud.com/www.ibm.com/clouduser!? —这表示您已成功通过了此应用程序实例的验证。
  3. 返回 Bluemix 仪表板,扩展该应用程序。打开应用程序概述页,单击 Instances 下的 ^ 按钮将实例数量递增到 2,然后单击 SAVE
  4. Bluemix 启动第二个实例。如果将鼠标悬停在 APP HEALTH 部分上,会看到两个实例正在运行。
  5. 关闭用于测试 Single Sign On 的浏览器会话,然后打开一个新的浏览器窗口或选项卡。浏览到 https://<your app name>.mybluemix.net 并单击 Login 按钮。 对 Single Sign On 执行身份验证,如果提示您是否共享个人信息,请选择同意。
  6. 这时不会看到简单的问候,很可能看到一个 ?04 not found?页面或一条错误消息,例如 揅annot GET /auth/sso/callback?scope=openid&code=EuPWIJBuCQdDjFbnGtgIAUsCiacMdE.?

第 4 步. 理解测试结果

使用单个实例时,这个简单的应用程序没有身份验证问题,但使用两个实例时存在该问题,因为此应用程序未采用 12 因素应用程序方法。 确切地讲,它违背了因素 6:?#x5C06;应用程序作为一个或多个无状态进程来执行?#x3002;

这种非故意的失败是 Bluemix 中的 Node.js 应用程序使用 Passport 和 express-session 中间件为 Bluemix Single Sign On 服务提供 OpenID Connect 支持的方式的副产品。express-session 服务将会话数据存储在内存中,所以该数据只能用于两个实例中的一个。当 Single Sign On 服务在验证用户后将浏览器重定向到回调 URL 时,如果将浏览器路由到另一个实例,Express Web 引擎将无法查找已验证用户的会话 ID,因此会抛出一条 404 消息。

此图演示了为什么一个会话中的数据只能用于应用程序中的实例 0:

Diagram showing session ID 1 available only to app instance 0
Diagram showing session ID 1 available only to app instance 0

解决方案是什么?因素 6 随后声明,?#x4EFB;何需要持久保存的数据必须存储在有状态的备份服务中,通常存储在数据库中。擥itHub 上的 express-session 文档列出了多个兼容的备份存储。您将使用 Redis 实现此持久性,它提供了一种内存型键-值缓存。此更改会将 express-session 的会话数据从实例内存中移出,然后将数据迁移到一个可供所有实例使用的持久存储中:

Diagram showing that after implementing persistence with Redis, session data is available to all instances
Diagram showing that after implementing persistence with Redis, session data is available to all instances

第 5 步. 使用 Redis 添加会话持久性

Bluemix 中的 Redis Cloud 服务托管在与您的应用程序相同的 SoftLayer 环境中,从而最大限度地缩短了访问此备份服务的响应时间。

  1. 在 Bluemix 中转到目录并从 Data and Analytics 类别中选择 Redis CloudScreenshot of the Redis Cloud tile in the Bluemix catalog's Data and Analytics category
    Screenshot of the Redis Cloud tile in the Bluemix catalog's Data and Analytics category
  2. App 列表中选择您的 Single Sign On 应用程序,然后从 Selected Plan 列表中选择 30MB。(此计划是免费的,而且对本教程中的会话而言,它有足够的空间。)
  3. 单击 CREATE 添加该服务并将它绑定到您的应用程序。
  4. 单击 RESTAGE 完成将服务添加到应用程序的过程。
  5. 在应用程序源代码的本地副本中,更新 package.json 中的 dependencies 节,在其中的第 14 行上添加一个逗号并添加另外两个条目:
      "passport-idaas-openidconnect":"1.0.x",
      "connect-redis":"2.4.x",
      "redis":"0.12.1"
    },
  6. 在 app.js 中,将 redisconnect-redis 添加到 require 部分,并将这部分附加到第 17 行:
    var OpenIDConnectStrategy = require('passport-idaas-openidconnect').IDaaSOIDCStrategy;
    var redis = require('redis');
    var RedisStore = require('connect-redis')(session);
  7. 在第 29 行,添加代码,以便从环境中获取 Redis Cloud 服务的配置细节,并连接到该服务:
    // get configuration for redis backing service and connect to service
    var redisConfig = appEnv.getService(/Redis.*/)
    var redisPort = redisConfig.credentials.port;
    var redisHost = redisConfig.credentials.hostname;
    var redisPasswd = redisConfig.credentials.password;
    
    var redisclient = redis.createClient(redisPort, redisHost, {no_ready_check: true});
    redisclient.auth(redisPasswd, function (err) {
        if (err) {
          throw err;
        }
    });
    
    redisclient.on('connect', function() {
        console.log('Connected to Redis');
    });
  8. 注释掉第 48 行附近 app.use(cookieParser()) 语句后面最初的 app.use(session(... 语句,并将它替换为一个代码块,使用 Redis 作为存储来初始化 express-session
    // define express-session services, etc. for SSO
    
    app.use(cookieParser());
    // app.use(session({resave:'true', saveUninitialized:'true' , secret:'keyboard cat'}));
    app.use(session({
      store: new RedisStore({ client: redisclient }),
      resave:'true',
      saveUninitialized:'true',
      secret:'top secr8t'
    }));
    app.use(passport.initialize());
    app.use(passport.session());
  9. 如果尚未保存 app.js 和 package.json,请保存它们。
  10. 通过命令行更新该应用程序:

    cf push

  11. 应用程序启动后,使用 Cloud Foundry logs 命令和 recent 选项:

    cf logs <your app name> --recent

  12. 查找一条表明应用程序启动时已连接到 Redis 的消息:Screenshot of log output from application showing Connected to Redis message
    Screenshot of log output from application showing Connected to Redis message
  13. manifest.yml 文件只指定了一个实例,所以该应用程序最初只有一个实例。使用应用程序概述页将实例数量增加到 2,然后保存更改。
  14. 返回位于 https://<your app name>.mybluemix.net/ 的应用程序,并重复第 3 步中的登录测试。

大功告成!现在该应用程序已可使用两个(或更多)实例正常运行。

结束语

在本教程中,您创建了一个使用 Bluemix Single Sign On 服务的简单应用程序,然后运行一两个实例来测试该应用程序。使用两个实例时,该应用程序出现了错误,因为 Node.js express-session 中间件默认情况下会使用一个本地内存存储。

借助 Bluemix 中的 Redis Cloud 服务,您通过为 express-session 会话添加持久存储解决了该问题。本教程重点介绍了一个关键的设计原则,让您能够通过流程模型扩展云应用程序。要实现最佳的扩展,每个流程都应设计为无状态的,而且应该始终将数据持久保存到可供所有流程使用的备份服务中。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, Security, Cloud computing
ArticleID=1020605
ArticleTitle=使用 Redis 和 Bluemix 上的 IBM Single Sign On 服务扩展身份验证
publish-date=11112015