我有一个react应用程序,使用express服务器的护照认证策略。在我的本地机器上,我的设置是在一个端口启动服务器(app.js),在另一个端口启动react应用。而且我能够使用护照成功认证。在托管环境中,服务器会负责启动服务器,并将react客户端建立到公共文件夹中。
我的问题是,当我把我的代码推送到托管环境后,托管环境启动了Express服务器(node app.js),并将react应用构建到公共文件夹。即使我能够使用护照进行身份验证,并且能够接收用户信息,但如果其他人从不同机器的不同浏览器登录,那么该用户的资料在我的浏览器中是可用的。
app.js
const express = require('express');
const passport = require('passport');
...
let user = {}; //this is an object to store the profile data
...
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
var OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
var Strategy = new OpenIDConnectStrategy({
clientID: settings.client_id,
clientSecret: settings.client_secret,
callbackURL: settings.callback_url,
function (iss, sub, profile, accessToken, refreshToken, params, done) {
process.nextTick(function () {
user = {...profile}
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
done(null, profile);
})
}
);
passport.use(Strategy);
app.use(express.static(__dirname + '/public'));
app.get('/login', passport.authenticate('openidconnect', {}));
app.get('/oidc_callback', function (req, res, next) {
passport.authenticate('openidconnect', {
successRedirect: redirect_url,
failureRedirect: '/failure',
})(req, res, next);
});
app.get('/user', function (req, res) { //This is the api i use to access user information in ract page
res.send(user);
});
app.get('/logout', function (req, res) {
user = {}; //empty the user data object
req.session.destroy();
req.logout();
res.end();
});
这里我们可以看到我使用了一个 user
对象来存储用户数据,并创建了一个 API /user
(app.get('/user' ...)
来访问我的客户端react应用程序的用户数据。
访问用户数据的React组件
constructor() {
super()
this.state = {
loggedUser: []
}
}
componentDidMount() {
axios.get('/user') //If I'm testing with local the API will be https://localhost:5000 - node server
.then(res => {
const loggedUser = res.data;
this.setState({ loggedUser });
}).catch(err => {
console.log("Fetch error", err)
})
}
编辑。 用新的数据编辑了问题后,完全复习了答案。
首先,我们需要一个唯一的键在 profile
来唯一标识一个用户,在我的例子中,我使用了 "oid"
但你可以使用更适合你的要求。
你可以尝试修改以下代码。
let user = {}; //this is an object to store the profile data
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
// Later ...
function(iss, sub, profile, accessToken, refreshToken, params, done) {
process.nextTick(function () {
user = {...profile}
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
done(null, profile);
})
}
with:
let uniqueKey = "oid"; // The field name of profile which uniquely identify a user
let users = {};
passport.serializeUser((user, done) => done(null, (users[user[uniqueKey]] = user)[uniqueKey]));
passport.deserializeUser((key, done) => done(null, users[key]));
// Later ...
(iss, sub, profile, accessToken, refreshToken, params, done) => done(null, { ...profile, accessToken, refreshToken })
// or
(iss, sub, profile, accessToken, refreshToken, params, done) => {
process.nextTick(() => done(null, { ...profile, accessToken, refreshToken }));
}
这些都是async函数,所以当我说的时候 返回 我的意思是通过 done
回调函数。
该 首次登录功能 只需退还 user
对象 passport-ci-oidc 似乎需要在 process.nextTick
,你可以尝试用或不用它)。)
serializeUser
确实需要 序列化 用户对象,在我们的例子中,这意味着只是将其存储在内存中。users[user[uniqueKey]] = user
然后返回唯一的密钥,以后护照应该用它来反序列化同一个用户。done(null, user[uniqueKey])
.
如上次 deserializeUser
需要通过给定的识别密钥来返回用户对象,在我们的例子中,只是为了从内存中返回它。done(null, users[key])
.
希望能帮到你