Bluemix 单点登录不显示登录页面

Bluemix Single Sign On doesn't show login page

我完成了使用 IoT Foundation 服务和 .js 样板可视化来自 raspberry pi 的数据的教程。

我遵循了以下教程:

https://developer.ibm.com/recipes/tutorials/visualizing-your-data/

一切正常。

现在我尝试添加单点登录服务以进行身份​​验证。我创建了一个云注册表并添加了两个测试用户。之后,我将该服务绑定到我的 IoT 可视化 .js 应用程序,并执行了将我的应用程序与该服务集成的步骤。为此,我遵循了官方文档步骤(点"Configuring a Node.js app"):

http://www.ng.bluemix.net/docs/services/SingleSignOn/configure_apps.html#tsk_configuringnodejsapp_express4

我在我的电脑上修改了文件并使用 CL CLI 上传了它们。问题是,它没有改变任何东西。我可以像以前一样访问我的应用程序,但我没有看到任何登录页面。

这是我的文件:

package.json

{
  "name": "iot-visualization",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "passport": "*",
    "cookie-parser": "*",
    "express-session": "*",
    "passport-idaas-openidconnect": "*",
    "express": "~4.2.0",
    "serve-favicon": "~2.1.0",
    "morgan": "~1.0.0",
    "cookie-parser": "~1.0.1",
    "body-parser": "~1.0.0",
    "debug": "~0.7.4",
    "jade": "~1.3.0",
    "stylus": "0.42.3",
    "express-session": "^1.8.1"
  }
}

app.js(URL修改)

/*******************************************************************************
* Copyright (c) 2014 IBM Corporation and other Contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial Contribution
*******************************************************************************/

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');


var index = require('./routes/index');

var app = express();

var http_host = (process.env.VCAP_APP_HOST || '0.0.0.0');
var http_port = (process.env.VCAP_APP_PORT || 7000);

app.set('port', http_port);
app.set('host',http_host);

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//use favicon
app.use(favicon(__dirname + '/public/images/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
// add session to store the api-key and auth token in the session
app.use(session({secret: 'xxxxxxxxxx',saveUninitialized: true,
                 resave: true}));
app.use(require('stylus').middleware(path.join(__dirname, 'public')));

var passport = require('passport'); 
var cookieParser = require('cookie-parser');
var session = require('express-session');

app.use(cookieParser());
app.use(session({resave: 'true', saveUninitialized: 'true' , secret: 'keyboard cat'}));
app.use(passport.initialize());
app.use(passport.session()); 

passport.serializeUser(function(user, done) {
   done(null, user);
}); 

passport.deserializeUser(function(obj, done) {
   done(null, obj);
});         

// VCAP_SERVICES contains all the credentials of services bound to
// this application. For details of its content, please refer to
// the document or sample of each service.  
var services = JSON.parse(process.env.VCAP_SERVICES || "{}");
var ssoConfig = services.SingleSignOn[0]; 
var client_id = ssoConfig.credentials.clientId;
var client_secret = ssoConfig.credentials.secret;
var authorization_url = ssoConfig.credentials.authorizationEndpointUrl;
var token_url = ssoConfig.credentials.tokenEndpointUrl;
var issuer_id = ssoConfig.credentials.issuerIdentifier;
var callback_url = 'https://xxxxx.mybluemix.net/auth/sso/callback';        

var OpenIDConnectStrategy = require('passport-idaas-openidconnect').IDaaSOIDCStrategy;
var Strategy = new OpenIDConnectStrategy({
                 authorizationURL : authorization_url,
                 tokenURL : token_url,
                 clientID : client_id,
                 scope: 'openid',
                 response_type: 'code',
                 clientSecret : client_secret,
                 callbackURL : callback_url,
                 skipUserProfile: true,
                 issuer: issuer_id}, 
    function(iss, sub, profile, accessToken, refreshToken, params, done)  {
                process.nextTick(function() {
        profile.accessToken = accessToken;
        profile.refreshToken = refreshToken;
        done(null, profile);
            })
}); 

passport.use(Strategy); 
app.get('/login', passport.authenticate('openidconnect', {})); 

function ensureAuthenticated(req, res, next) {
    if(!req.isAuthenticated()) {
                req.session.originalUrl = req.originalUrl;
        res.redirect('/login');
    } else {
        return next();
    }
}

app.get('/auth/sso/callback',function(req,res,next) {               
             var redirect_url = req.session.originalUrl;                
             passport.authenticate('openidconnect', {
                     successRedirect: redirect_url,                                
                     failureRedirect: '/failure',                        
          })(req,res,next);
        });

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

app.use(express.static(path.join(__dirname, 'public')));


app.use('/',index);

app.use(function(req, res, next) {
    if(req.session.api_key)
    res.redirect("/dashboard");
  else
    res.redirect('/login');
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

var server = app.listen(app.get('port'), app.get('host'), function() {
  console.log('Express server listening on ' + server.address().address + ':' + server.address().port);
});

module.exports = app;

有什么想法吗?

// 编辑

刚开始教程的时候没有.cfignore文件。所以我在我的应用程序根文件夹中创建了一个包含以下内容的文件:

node_modules/passport
node_modules/cookie-parser
node_modules/express-session
node_modules/passport-idaas-openidconnect

这是否正确以及为什么我之前没有包含教程内容的此文件:

node_modules

您需要将 ensureAuthenticated 函数添加到您的 express 中间件堆栈中。每当向您的应用程序发出请求时,都需要调用此函数。例如,您可以通过添加以下内容将其添加到发送到您的应用程序的所有请求中:

app.use(ensureAuthenticated);

首先我假设变量callback_url的值为'xxxxx.mybluemix.net/auth/sso/callback'为例。如果不是,您应该将 'xxxxx' 替换为您的应用程序名称。

Single Sign On - Configuring a Node.js app 文档中所述:

The passport-idaas-openidconnect module works with passport versions 0.1.1 up to 0.3.2. Versions later than 0.3.2 might not work correctly.

我会确保您使用的是正确的护照版本,使用(例如)package.json

中的这一行
"passport": "^0.2.2",

如果您愿意,可以出于测试目的简化回调函数,如下所示(它可能会抛出找不到 req.session.originalUrl 的错误)并在以后扩展它:

app.get('/auth/sso/callback',function(req,res,next) {               
    passport.authenticate('openidconnect', {
                                         successRedirect: "/home",                              
                                         failureRedirect: '/failure',                        
                                        }
                      )(req,res,next);
 });

你的其余代码对我来说似乎没问题,因为已经有人建议你必须将 "ensureAuthenticated" 函数链接到你想要的每个 app.get、app.post 等接受认证。

例如尝试做类似的事情:

app.get('/home', ensureAuthenticated, function(req, res) { 
   var htmlSplashPage = "<!DOCTYPE html> <html> <body> <h1>Hello "+JSON.stringify(req.session.passport.user._json.displayName)+"</h1></body> </html>"; 
   res.writeHead(200, {'Content-Type': 'text/html','Content-Length':htmlSplashPage.length});
   res.write(htmlSplashPage);
   res.end();
 });

在调用 /home GET 函数 ensureAuthenticated 之前调用函数 ensureAuthenticated ,只有当用户已经通过身份验证时,才会执行下一个函数(home),否则您将被重定向到登录页面。