Woo*_*man 5 node.js express openid-connect
我的 Express 应用程序调用 request.isAuthenticated() 方法。但是,我不知道它会检查什么来确定它是否经过身份验证。我的应用程序需要通过 OIDC 进行身份验证。如何告诉 isAuthenticated() 方法它通过了 OIDC 身份验证?
目前,我将其设置为重定向到具有适当 client_id、范围的 OIDC 授权端点。用户的浏览器遵循重定向,用户成功登录。OIDC 将重定向发送回我的 Express 应用程序提供的回调。用户浏览器成功到达此端点。
我的综合文件在下面的一篇文章中。因为我是 Node 的新手,所以它比我想要的要草率。另外,因为我无法让 Visual Code 捕获我的断点(请参阅我的其他相关帖子),所以我只能使用 console.log 语句进行调试。
如果我在浏览器中访问 /cost-recovery,它会转到以下路线:
app.use('/cost-recovery*', saveUrlInSession, /*ensureAuthenticated*/ isLoggedIn,createProxyMiddleware(sprint_cost_recovery_options));
Run Code Online (Sandbox Code Playgroud)
它将 URL 保存在会话中,允许回调到达我想要的地方。这样可行。在 EnsureAuthenticated 和 isLoggerdIn 处理程序中,系统重定向到 OIDC/OpenId/?? ID登录页面。我可以登录,然后返回到我的回调页面。在该回调路由中,req.isAuthenticated()仍然显示 false。
也许因为我正在使用这个护照模块,所以它不知道登录发生了。正在设置 cookie,在紧要关头我可以检查它们来代替工作 req.isAuthenticated() 方法,但我宁愿使用提供的工具。
/**
* How the application respond to clients requests depending of the endpoint
*/
const userController = require('../controllers/userController');
var OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
const strategyConfiguration = require('../../config/strategy.json');
console.log('strategyConfiguration=' + JSON.stringify(strategyConfiguration));
const passport = require('passport');
const https = require('https');
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
console.log('App setting title=' + app.get('title'));
console.log('App env=' + app.get('env'));
console.log('App setting query parser=' + app.get('query parser'));
console.log('App setting string routing=' + app.get('strict routing'));
console.log('App setting case sensitive routing=' + app.get('case sensitive routing'));
var http = require('http');
var url = require('url');
var currentOriginalUrl;
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
// openid-client is an implementation of the OpenID Relying Party (RP, Client) server
// for the runtime of Node.js, support passport
//OAuth 2.0 protocol
//middleware Passport-OpenID Connect
const config = require('../configuration/config').getConfiguration();
console.log('config=' + JSON.stringify(config));
console.log('strategyConfiguration=' + JSON.stringify(strategyConfiguration));
var OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
var Strategy = new OpenIDConnectStrategy({
discoveryURL: strategyConfiguration.discoveryURL,
clientID: strategyConfiguration.clientID,
scope: 'openid',
response_type: 'code',
clientSecret: strategyConfiguration.clientSecret,
callbackURL: strategyConfiguration.callbackURL,
skipUserProfile: true, /* this was true before */
CACertPathList: [
`/certs/DigiCertGlobalRootCA.crt`,
`/certs/DigiCertSHA2SecureServerCA.crt`,
]
},
function (iss, sub, profile, accessToken, refreshToken, params, done) {
process.nextTick(function () {
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
const userDetails = profile._json;
const userProfile = {
uid: userDetails.uid,
mail: profile.id,
cn: decodeURIComponent(userDetails.cn),
exp: 60 * 60 /*TODO: Get proper number of seconds. userDetails.exp */,
blueGroups: userDetails.blueGroups,
};
done(null, userProfile);
})
}
)
var proxy_server = require('http-proxy').createProxyServer({});
const originalUrl = new URL(config.host);
console.log('matched cost-recovery using original url: ' + originalUrl);
const newUrl = new URL(originalUrl);
newUrl.port = 8447;
console.log('matched cost-recovery new url' + newUrl);
function saveUrlInSession(request, response, next) {
if (request.params.state) {
console.log('Saving state=' + request.params.state + " in session");
request.session.savedUrl = request.request.params.state;
} else {
console.log('Saving originalUrl=' + request.originalUrl + " in session");
request.session.savedUrl = request.originalUrl;
}
if (next) {
return next();
} else {
console.log('@@ no next');
}
}
function ensureAuthenticated(req, res, next) {
if (!req.isAuthenticated()) {
console.log('@@ ensureAuthenticated reached. Not authenticated. redirecting to /login');
res.redirect('/login')
} else {
console.log('@@ ensureAuthenticated reached. Authenticated. Continuing to next handler');
return next();
}
}
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
console.log('@@isLoggedIn req.isAuthenticated()=true');
req.session.isAuthenticated = true;
res.locals.isAuthenticated = true;
res.locals.user = req.user;
next(); //If you are authenticated, run the next
} else {
console.log('@@isLoggedIn req.isAuthenticated()=false');
return res.redirect("/login");
}
}
function getUserProfile(req, res, next) {
console.log('@@ reached getUserProfile')
if (typeof req.user == 'undefined') {
res.status(401);
next();
}
return res.status(200).send(req.user);
}
function getUserName(req, res, next) {
console.log('@@ reached getUserName')
if (typeof req.user === 'undefined') {
res.status(401);
return next();
}
return res.status(200).send(req.user.cn);
}
var newURL = url.format({
protocol: config.protocol,
host: config.host,
pathname: config.originalUrl
});
console.log('newURL=' + newURL);
var newURL2 = new URL(newURL);
newURL2.port = "8447";
newURL2.protocol = "http";
console.log('newURL2=' + newURL2);
const sprint_cost_recovery_options = {
target: newURL2,
level: 'debug',
changeOrigin: true,
ws: true
}
console.log('@@ sprint_cost_recovery_options=' + JSON.stringify(sprint_cost_recovery_options));
passport.use(Strategy);
app.use(passport.initialize());
app.use(passport.session());
app.use(function (request, response, next) {
console.log('Common Route: Incoming request originalUrl:' + request.originalUrl);
console.log('Common Route: Incoming request previous Url:' + request.header('referer'));
console.log('Common Route: Incoming request url:' + request.url);
next();
});
app.get('/auth/sso/callback/:callback_uri?'
, function (request, response, next) {
console.log('CB-1 matched on originalUrl=' + request.originalUrl);
console.log('@@ CB-2. isAuthenticated=' + request.isAuthenticated());
console.log('@@ CB-2.5 request.account test=' + request.account);
console.log('@@ savedUrl in session=' + request.session.savedUrl);
//var redirectUrl = poppedUrlFromSession(request);
var redirectUrl = request.session.savedUrl;
if (!redirectUrl) {
redirectUrl = "/health-check";
}
console.log('@@ CB-3. redirectUrl=' + redirectUrl);
console.log('@@ CB-4. before passport.authenticate');
console.log('@@ CB-5. after passport.authenticate');
console.log('@@ CB-6. isAuthenticated=' + request.isAuthenticated());
console.log('@@ auth-sso-callback-2 bp1');
response.redirect(redirectUrl);
}
);
app.use('/login?:state?',
function (request, response, next) {
var stateIndicator = (request.params.state) ? " with state " + request.params.state : " with no state/redirect.";
console.log('@@ Reached login with ' + stateIndicator);
return next();
},
passport.authenticate('openidconnect', { state: Math.random().toString(36).substr(2, 10) }));
app.use('/rules/username', saveUrlInSession, ensureAuthenticated, userController.getUserName);
app.use('/rules/profile', saveUrlInSession, ensureAuthenticated, userController.getUserProfile);
app.use('/cost-recovery*', saveUrlInSession, /*ensureAuthenticated*/ isLoggedIn,createProxyMiddleware(sprint_cost_recovery_options));
app.use('/profile', saveUrlInSession, ensureAuthenticated, getUserProfile);
app.use('/username', saveUrlInSession, ensureAuthenticated, getUserName);
app.get('/successful-login', function (req, res) {
res.send('login succeeded');
});
app.get('/failure', function (req, res) {
res.send('login failed');
});
app.get('/health-check', (request, response) => {
response.send('Middleware is running.');
});
};
Run Code Online (Sandbox Code Playgroud)
简而言之,大多数时候req.isAuthenticated只是检查该值是否req.user已设置,但详细信息可能会根据您的 Passport 配置而变化。
我想您可能已经清楚了,该方法是由Passport.jsisAuthenticated添加到对象中的。req
由于其他人似乎不清楚的原因,该方法似乎没有任何面向公众的文档。
但是你可以在护照的http/request.js源代码中找到req.isAuthenticated(also )的实现。req.isUnauthenticated
目前的原始代码是这样的:
req.isAuthenticated = function() {
var property = 'user';
if (this._passport && this._passport.instance) {
property = this._passport.instance._userProperty || 'user';
}
return (this[property]) ? true : false;
};
Run Code Online (Sandbox Code Playgroud)
(我查看的 request.js 版本中的第 77-90 行。)
正如您所看到的,这个基本实现本质上是(1)弄清楚护照的userProperty设置是什么以及(2)检查是否req[userProperty]“真实”。
(该userProperty值是 Passport 的另一个未充分记录或可能未记录的功能。您可能可以假设该值是,user除非您已采取措施将其设为其他值。)
因此,有效地isAuthenticated应该返回trueifreq.user已设置为非空对象以及falseif req.useris nullor falseor0等。
您可能知道,在一般情况下,通行证策略将设置req.user为有关经过身份验证的用户的属性映射,作为req.login函数的一部分(由passport.authenticate中间件间接调用)。因此,一般来说,在调用req.loginor后passport.authenticate,您应该期望req.user被填充,因此req.isAuthenticated返回 true。
由于这种情况没有发生,我猜测其中之一正在发生。
该login函数或authenticate中间件实际上并未在您期望的时候被调用。
该函数正在被调用,但身份验证本身失败(因此isAuthenticated() === false技术上是正确的)。
身份验证成功,但个人资料信息未保存为req.user.
在已知登录后检查请求对象可能会清楚地表明用户信息是否正在存储,如果是,则存储在何处。
扫描您共享的代码,看起来您还希望在您的应用程序中找到用户个人资料信息req.user,因此,如果这完全有效,我希望req.isAuthenticated能够正常工作,但我不确定我是否完全了解您的整体状态。
我特别不熟悉password-ci-oidc(虽然我在 npm 上看到该模块,但它看起来不像原始源代码是公开的),但您可能想深入检查它是否req.user正在userProperty使用和/或是否它完全填充了一个用户对象。
特别是skipUserProfile: true你的策略配置中的一点让我印象深刻。您是否有可能实际上告诉策略中间件不要填充req.user?
独立于您最初的问题,另一件事要注意的是,如果您有一种req.isAuthenticated()更req.user ? true : false可靠的方法来验证用户是否经过身份验证,那么仅使用它可能就足够了(或者猴子补丁req.isAuthenticated到使用您的逻辑而不是默认行为)。无论如何,它似乎并没有做更多的事情。
| 归档时间: |
|
| 查看次数: |
8204 次 |
| 最近记录: |