从关于护照集成loopback-example-passport的现有环回示例开始,我正在尝试集成基于openId的外部IDP,在我的案例中是KeyCloak。
这里是原始server.js代码的示例
'use strict';
var loopback = require('loopback');
var boot = require('loopback-boot');
var app = module.exports = loopback();
var cookieParser = require('cookie-parser');
var session = require('express-session');
// Passport configurators..
var loopbackPassport = require('loopback-component-passport');
var PassportConfigurator = loopbackPassport.PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);
/*
* body-parser is a piece of express middleware that
* reads a form's input and stores it as a javascript
* object accessible through `req.body`
*
*/
var bodyParser = require('body-parser');
/**
* Flash messages for passport
*
* Setting the failureFlash option to true instructs Passport to flash an
* error message using the message given by the strategy's verify callback,
* if any. This is often the best approach, because the verify callback
* can make the most accurate determination of why authentication failed.
*/
var flash = require('express-flash');
// attempt to build the providers/passport config
var config = {};
try {
config = require('../providers.json');
} catch (err) {
console.trace(err);
process.exit(1); // fatal
}
// -- Add your pre-processing middleware here --
// Setup the view engine (jade)
var path = require('path');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// boot scripts mount components like REST API
boot(app, __dirname);
// to support JSON-encoded bodies
app.middleware('parse', bodyParser.json());
// to support URL-encoded bodies
app.middleware('parse', bodyParser.urlencoded({
extended: true,
}));
// The access token is only available after boot
app.middleware('auth', loopback.token({
model: app.models.accessToken,
}));
app.middleware('session:before', cookieParser(app.get('cookieSecret')));
app.middleware('session', session({
secret: 'kitty',
saveUninitialized: true,
resave: true,
}));
passportConfigurator.init();
// We need flash messages to see passport errors
app.use(flash());
passportConfigurator.setupModels({
userModel: app.models.user,
userIdentityModel: app.models.userIdentity,
userCredentialModel: app.models.userCredential,
});
for (var s in config) {
var c = config[s];
c.session = c.session !== false;
passportConfigurator.configureProvider(s, c);
}
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
app.get('/', function(req, res, next) {
console.debug("Passo di qui");
res.render('pages/index', {user:
req.user,
url: req.url,
});
});
app.get('/auth/account', ensureLoggedIn('/login'), function(req, res, next) {
res.render('pages/loginProfiles', {
user: req.user,
url: req.url,
});
});
app.get('/local', function(req, res, next) {
res.render('pages/local', {
user: req.user,
url: req.url,
});
});
app.get('/ldap', function(req, res, next) {
res.render('pages/ldap', {
user: req.user,
url: req.url,
});
});
app.get('/signup', function(req, res, next) {
res.render('pages/signup', {
user: req.user,
url: req.url,
});
});
app.post('/signup', function(req, res, next) {
var User = app.models.user;
var newUser = {};
newUser.email = req.body.email.toLowerCase();
newUser.username = req.body.username.trim();
newUser.password = req.body.password;
User.create(newUser, function(err, user) {
if (err) {
req.flash('error', err.message);
return res.redirect('back');
} else {
// Passport exposes a login() function on req (also aliased as logIn())
// that can be used to establish a login session. This function is
// primarily used when users sign up, during which req.login() can
// be invoked to log in the newly registered user.
req.login(user, function(err) {
if (err) {
req.flash('error', err.message);
return res.redirect('back');
}
return res.redirect('/auth/account');
});
}
});
});
app.get('/login', function(req, res, next) {
res.render('pages/login', {
user: req.user,
url: req.url,
});
});
app.get('/auth/logout', function(req, res, next) {
req.logout();
res.redirect('/');
});
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
var baseUrl = app.get('url').replace(/\/$/, '');
console.log('Web server listening at: %s', baseUrl);
if (app.get('loopback-component-explorer')) {
var explorerPath = app.get('loopback-component-explorer').mountPath;
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
}
});
};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
这里是我的providers.json定义
{
"local": {
"provider": "local",
"module": "passport-local",
"usernameField": "username",
"passwordField": "password",
"authPath": "/auth/local",
"successRedirect": "/auth/account",
"failureRedirect": "/local",
"failureFlash": true
},
"keycloak": {
"provider": "keycloak",
"module": "passport-openid-connect",
"authScheme": "openid connect",
"scope": "openid",
"passReqToCallback":true,
"session": true,
"issuerHost": "https://[my host]/auth/realms/[my realm]",
"client_id": "[my client id]",
"client_secret": "[my client secret]",
"redirect_uri": "http://localhost:3000/auth/account",
"authPath": "/auth/keycloak",
"callbackPath": "/auth/keycloak/callback",
"response_type":"code",
"usePKCE": false,
"link":true
}
}
测试idp我能够被重定向,登录并返回但我从未登录过,req.user始终是未定义的。有什么遗失?
由我自己解决,希望帮助他人。我使用了另一个护照组件,passport-openidconnect而不是passport-openid-connect。
这是添加到loopback-passport-example的提供程序
"openid": {
"provider": "openid",
"module": "passport-openidconnect",
"issuer": "https://[my idp]/auth/realms/[my realm]",
"session": "true",
"clientID": "[my client id]",
"clientSecret": "[my client secret]",
"callbackURL": "/auth/openid/callback",
"authorizationURL": "[auth url]",
"tokenURL": "[token url]",
"userInfoURL": "[user info url]",
"scope": "auth_web openid profile email",
"authPath": "/auth/openid",
"callbackPath": "/auth/openid/callback",
"successRedirect": "/auth/account",
"failureRedirect": "/login",
"failureFlash": true
}
请记住将/ auth / openid添加到示例登录页面。