了解 Node.js 应用程序与 Oracle Identity Cloud Service 之间的验证

您已准备好了解 Node.js Web 应用程序与 Oracle Identity Cloud Service 之间的验证。这包括了解以下内容:

  • Oracle Identity Cloud Service 为 Node.js SDK 支持的三路验证流

  • 将 SDK 与 Node.js 应用结合使用以通过 Oracle Identity Cloud Service 进行验证的用例

  • Node.js SDK 的方法和函数

了解三路验证流

Oracle Identity Cloud Service 支持 Node.js SDK 的三路验证流。在此流中,用户直接与 Oracle Identity Cloud Service 交互。用户登录后,Oracle Identity Cloud Service 会发出 SDK 为用户访问令牌交换的授权代码。Node.js Web 应用程序使用此访问令牌向用户授予对应用程序中受保护资源的访问权限。三路流使用授权代码授权类型。

为了提高安全性,Oracle 建议您使用三路流程将 Node.js Web 应用程序与 Oracle Identity Cloud Service 集成以进行验证。通过使用授权代码授权类型,您还可以访问受 Oracle Identity Cloud Service 保护的其他应用程序,而无需重新验证。

了解将 SDK 与 Node.js 应用程序结合使用的主要用例

Node.js Web 应用程序实现两个用例:一个用于验证用户,另一个用于访问有关登录用户的详细信息。

以下数据流图说明了 Web 浏览器、Web 应用程序和 Oracle Identity Cloud Service 之间每个用例的事件、调用和响应的流。

用例 1:验证用户

数据流以以下方式进行:

  1. 用户请求受保护的资源。

  2. 验证模块使用 SDK 为 Oracle Identity Cloud Service 生成请求授权代码 URL,并将此 URL 作为重定向响应发送到 Web 浏览器。

  3. Web 浏览器调用 URL。

  4. 此时将显示 Oracle Identity Cloud Service 登录页。

  5. 用户提交其 Oracle Identity Cloud Service 登录身份证明。

  6. 用户登录后,Oracle Identity Cloud Service 将为用户创建会话并发出授权代码。

  7. Web 应用程序进行后端(或服务器到服务器)调用以交换访问令牌的授权代码。

  8. Oracle Identity Cloud Service 发出访问令牌和 ID 令牌。

  9. 将建立会话,并将用户重定向到主页

  10. 此时将显示 Web 应用程序的主页

用例 2:获取有关用户的详细信息

数据流以以下方式进行:

  1. 用户请求 /myProfile 资源。

  2. Web 应用程序使用 Oracle Identity Cloud Service 的 SDK 验证 ID 令牌。

  3. 从 ID 标记验证返回的数据包含 JSON 对象格式的用户详细信息。

  4. 我的概要信息页将 JSON 对象呈现为 HTML 内容。

了解方法和函数

Node.js SDK 是添加到 Node.js modules 文件夹中的 Node.js 护照策略。此 SDK 还基于 Node.js 承诺。

SDK 需要的所有第三方相关项都在 SDK 的 package.json 文件中定义,该文件位于从 Oracle Identity Cloud Service 控制台下载的 Node.js SDK zip 文件中。您至少需要在 Node.js Web 应用程序中使用这组模块。

"dependencies": {
    "async": "^2.1.2",
    "bunyan": "^1.8.5",
    "cache-manager": "^2.2.0",
    "json-web-token": "^2.1.3",
    "jsonwebtoken": "^8.2.1",
    "jwk-to-pem": "^1.2.6",
    "jws": "^3.1.5",
    "lru": "^3.1.0",
    "passport": "^0.4.0",
    "promise": "^8.0.1",
    "querystring": "^0.2.0",
    "request": "^2.81.0",
    "rsa-pem-to-jwk": "^1.1.3",
    "util": "^0.10.3"
  },

Node.js Web 应用程序是使用 Node.js expressexpress-handlebars 模块开发的,这些模块以每个 URL 的 app.get() 函数形式实现 URL 路由。

Node.js SDK 需要加载 Oracle Identity Cloud Service 连接信息的 JSON 变量。Node.js Web 应用程序使用 ids 变量存储以下信息:

var ids = {
    oracle: {
    "ClientId": "123456789abcdefghij'",
    "ClientSecret": "abcde-12345-zyxvu-98765-qwerty",
    "ClientTenant": "idcs-abcd1234",
    "IDCSHost": "https://%tenant%.identity.oraclecloud.com",
    "AudienceServiceUrl" : "https://idcs-abcd1234.identity.oraclecloud.com",
    "TokenIssuer": "https://identity.oraclecloud.com/",
    "scope": "urn:opc:idm:t.user.me openid",
    "logoutSufix": "/oauth2/v1/userlogout",
    "redirectURL": "http://localhost:3000/callback",
    "LogLevel":"INFO",
    "ConsoleLog":"True"
    }
};
module.exports = ids;

以下是此 SDK 的每个必需属性的简要说明:

名称 说明
ClientId Oracle Identity Cloud Service 控制台中注册 Node.js Web 应用程序后生成的客户端 ID 的值。
ClientSecret Oracle Identity Cloud Service 控制台中注册 Node.js Web 应用程序后生成的客户端密钥的值。
ClientTenant Oracle Identity Cloud Service 实例的域前缀。此前缀通常与 idcs-abcd1234 类似。
IDCSHost Oracle Identity Cloud Service 实例的域后缀。在运行时, %tenant% 占位符将替换为 ClientTenant 属性的值。
AudienceServiceUrl Oracle Identity Cloud Service 实例的全限定域名 URL。
TokenIssuer 对于此属性,Oracle 建议您保留值 https://identity.oraclecloud.com/
scope

该范围控制应用程序可以代表 Oracle Identity Cloud Service 用户访问或处理的数据。

如果应用程序使用 SDK 对用户进行验证,则范围为 openid。如果应用程序使用 SDK 获取有关用户的详细信息,则范围为 urn:opc:idm:t.user.me openid

ConsoleLog 启用 SDK 日志。
LogLevel 指示 SDK 的日志级别。

应用程序同时使用 logoutSufixredirectURL 属性来避免对这些值进行硬编码。SDK 不需要它们。

Node.js 应用程序实施 /oauth/oracle URL 路由。当用户使用 Oracle Identity Cloud Service 进行验证时,Web 浏览器会向此 URL 发出 GET 请求。此路由使用 SDK 生成 Oracle Identity Cloud Service 的授权 URL。

//Loading the configurations
var auth = require('./auth.js');
 
//Route for /oauth/oracle
app.get("/auth/oracle", function(req, res){
    //Authentication Manager loaded with the configurations.
    am = new IdcsAuthenticationManager(auth.oracle);
    //Using Authentication Manager to generate the Authorization Code URL, passing the
    //application's callback URL as parameter, along with code value and code parameter.
    am.getAuthorizationCodeUrl(auth.oracle.redirectURL, auth.oracle.scope, "1234", "code")
        .then(function(authZurl){
            //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
            res.redirect(authZurl);
        }).catch(function(err){
            res.end(err);
        })
});

此函数将 JSON 参数加载到变量,初始化验证管理器,并使用 Node.js SDK 的 IdcsAuthenticationManager.getAuthorizationCodeUrl() 函数生成授权代码 URL。此函数使用 promise 在生成授权代码 URL 时重定向用户的 Web 浏览器,或者在浏览器中呈现错误。

以下参数用于生成授权代码 URL:

名称 说明
auth.oracle.redirectURL 用户登录后,Oracle Identity Cloud Service 会将用户的 Web 浏览器重定向到此 URL。此 URL 必须与您在 Identity Cloud Service 控制台中为可信应用程序配置的 URL 匹配。有关为 Node.js Web 应用程序指定重定向 URL 的详细信息,请参阅注册 Node.js 应用程序。
auth.oracle.scope 验证的 OAuth 或 OpenID Connect 范围。此应用程序仅需要 openid 验证。
state OAuth 协议定义此参数。示例 Node.js Web 应用程序使用此代码检查是否可以与 Oracle Identity Cloud Service 建立通信。对于此示例,此参数的值为 1234
response_type 授权代码授权类型所需的参数。对于此示例,此参数的值为 code

用户登录后,Oracle Identity Cloud Service 会将用户的 Web 浏览器重定向到回调 URL,开发人员必须实施该 URL。Node.js Web 应用程序使用 /callback 路由来处理此请求。

//Route for /callback
app.get("/callback", function(req,res){
    //Authentication Manager loaded with the configurations.
    var am = new IdcsAuthenticationManager(auth.oracle);
    //Getting the authorization code from the "code" parameter
    var authZcode = req.query.code;
    //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
    am.authorizationCode(authZcode)
        .then(function(result){
            //Getting the Access and Id Token Values to set in the session.
            req.session.access_token = result.access_token;
            req.session.id_token = result.id_token;
            res.cookie(config.IDCS_COOKIE_NAME, result.access_token);
            res.header('idcs_user_assertion', result.access_token)
            res.redirect('/auth.html');
        }).catch(function(err){
            res.end(err);
        })
});

Node.js 应用程序使用授权代码请求访问令牌。访问令牌存储为 Cookie,然后将其发送到 Web 浏览器以供将来使用。

Node.js SDK 的 IdcsAuthenticationManager.authorizationCode() 函数还使用 promise(即 then-catch 语句)将访问令牌设置为 cookie,并将浏览器重定向到 /auth.html 页面。

Node.js SDK 基于 Node.js 护照框架。因此,浏览器必须将访问令牌作为头变量转发到 /auth URL 处理程序,并将 passport.authenticate() 方法与 Oracle Identity Cloud Service 策略名称一起使用作为参数:

//Uses passport to create a User Session in Node.js.
//Passport sets a user attribute in the request as a json object.
app.get('/auth', passport.authenticate(config.IDCS_STRATEGY_NAME, {}), function(req, res) {
   res.redirect('/home');
});

passport.authenticate() 方法创建应用程序的会话后,该函数会将用户的 Web 浏览器重定向到 /home 应用程序中的受保护 URL。除了 /home,Node.js Web 应用程序还有另一个受保护的 URL:/myProfile

任何受保护的 URL 都需要检查用户会话是否是以前创建的。以下函数由每个 app.get() 函数用于这些 URL。

function ensureAuthenticated(req, res, next) {
   if (req.isAuthenticated()) {
      return next();
   }
   res.redirect('/login')
}

Node.js 应用程序处理 /myProfile 路由并获取会话中设置的信息,如下所示:

app.get("/myProfile", ensureAuthenticated, function(req,res){
   //User Manager loaded with the configurations
   var am = new IdcsAuthenticationManager(auth.oracle);
   //Validating id token to acquire information such as UserID, DisplayName, list of groups and AppRoles assigned to the user.
   am.validateIdToken(req.session['id_token'])
    .then(function(idToken){
      res.render('myProfile', {
         layout: 'privateLayout',
         title: 'My Profile',
         user: req.user,
         userInfo: JSON.stringify(idToken, null, 2)
         });
    }).catch(function(err1){
       res.end(err1);
   })
});

初始化 IdcsAuthenticationManager 对象后,/myProfile 路由的处理程序使用 SDK 的 IdcsAuthenticationManager.validateIdToken() 函数获取用户信息,例如显示名称、用户 ID 以及分配给用户的组和应用程序角色的列表。然后,JSON 对象将解析为 myProfile.handlebars 文件的字符串,以在 Web 浏览器中呈现。

要从应用程序与 Oracle Identity Cloud Service 之间的单点登录注销用户,Node.js Web 应用程序将实施 /logout 路由,如下所示:

app.get('/logout', function(req, res){
  var id_token = req.session.id_token;
  var logouturl = auth.oracle.AudienceServiceUrl + auth.oracle.logoutSufix + '?post_logout_redirect_uri=http%3A//localhost%3A3000&id_token_hint='+ id_token;
  req.session.destroy(function(err) {
    if(err) {
      console.log(err);
    } else {
      req.logout();
      res.clearCookie();
      res.redirect(logouturl);
    }
  })
});

此路由会使应用程序的会话无效,删除之前设置的任何对象和 Cookie,然后将用户的 Web 浏览器重定向到 Oracle Identity Cloud Service 的 OAuth 注销 URL。