所以我正在设计一个带有nodejs的应用程序,我需要创建一个用户论坛。我决定不再重新发明轮子,所以我选择使用nodebb。但是,我的应用程序有用户登录,节点bb也是如此,我希望用户登录到我的站点后自动登录nodebb。我之前从未使用过oauth2orize,但这就是我想出来的:
server.grant(oauth2orize.grant.code(function(client, redirectUri, user, ares, callback) {
// Create a new authorization code
var code = new Code({
value: uid(16),
clientId: client._id,
redirectUri: redirectUri,
userId: user._id
});
// Save the auth code and check for errors
code.save(function(err) {
if (err) { return callback(err); }
callback(null, code.value);
});
}));
// Exchange authorization codes for access tokens
server.exchange(oauth2orize.exchange.code(function(client, code, redirectUri, callback) {
console.log(client, code, redirectUri)
Code.findOne({ value: code }, function (err, authCode) {
if (err) { return callback(err); }
console.log(authCode.clientId,client._id);
if (authCode === undefined) { return callback(null, false); }
if (client._id.toString() !== authCode.clientId) { return callback(null, false); }
//if (redirectUri !== authCode.redirectUri) { return callback(null, false); }
// Delete auth code now that it has been used
authCode.remove(function (err) {
if(err) { return callback(err); }
// Create a new access token
var token = new Token({
value: uid(256),
clientId: authCode.clientId,
userId: authCode.userId
});
// Save the access token and check for errors
token.save(function (err) {
if (err) { return callback(err); }
callback(null, token);
});
});
});
}));
module.exports.authorization = [
server.authorization(function(clientId, redirectUri, callback) {
Client.findOne({ id: clientId }, function (err, client) {
if (err) { console.log("I ran herea");return callback(err); }
return callback(null, client, redirectUri);
});
}, function (client, user, redirectUri, done) {
console.log(redirectUri);
setCodes(client, user, redirectUri, Code);
Code.find({
clientId: client.id,
userId: user._id
}, function (err, codes) {
console.log(codes);
if (err) { console.log("second"); return done(err); }
if (codes.length > 0) {
console.log("third")
return done(null, true);
} else {
console.log('I ran here fourth');
return done(null,false);
}
});
})
]
// Application client token exchange endpoint
module.exports.token = [
server.token(),
server.errorHandler()
]
module.exports.getNodebbUsers = function(req, res){
console.log(req.body.token);
Token.find({value : req.body.token}, function(error, user){
userId = user[0].userId;
if(!error){
User.find({_id : userId}, function(error, user){
console.log(userId);
if(!error){
res.json({
username : user[0].userName,
email : user[0].email,
id : user[0]._id
})
} else {
console.log(error);
}
})
}
})
}
这是我的oauth2orize代码块,它适用于邮递员。
但是,这是我应该编辑和使用的nodebb上的插件。我已经编辑过了,我现在真的很难过。
var constants = Object.freeze({
type: 'oauth2', // Either 'oauth' or 'oauth2'
name: 'create-and-login-user', // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
oauth: {
requestTokenURL: '',
accessTokenURL: '',
userAuthorizationURL: '',
consumerKey: '',
consumerSecret: ''
},
oauth2: {
authorizationURL: '/api/oauth2/authorize',
tokenURL: '/api/oauth2/token',
clientID: 'nodeBB_logIn',
clientSecret: 'change_this_later'
},
userRoute: '/api/oauth2/users' // This is the address to your app's "user profile" API endpoint (expects JSON)
}),
configOk = false,
OAuth = {}, passportOAuth, opts;
if (!constants.name) {
winston.error('[sso-oauth] Please specify a name for your OAuth provider (library.js:32)');
} else if (!constants.type || (constants.type !== 'oauth' && constants.type !== 'oauth2')) {
winston.error('[sso-oauth] Please specify an OAuth strategy to utilise (library.js:31)');
} else if (!constants.userRoute) {
winston.error('[sso-oauth] User Route required (library.js:31)');
} else {
configOk = true;
}
OAuth.getStrategy = function(strategies, callback) {
if (configOk) {
passportOAuth = require('passport-oauth')[constants.type === 'oauth' ? 'OAuthStrategy' : 'OAuth2Strategy'];
if (constants.type === 'oauth') {
// OAuth options
opts = constants.oauth;
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
passportOAuth.Strategy.prototype.userProfile = function(token, secret, params, done) {
this._oauth.get(constants.userRoute, token, secret, function(err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
try {
var json = JSON.parse(body);
OAuth.parseUserReturn(json, function(err, profile) {
if (err) return done(err);
profile.provider = constants.name;
done(null, profile);
});
} catch(e) {
done(e);
}
});
};
} else if (constants.type === 'oauth2') {
// OAuth 2 options
opts = constants.oauth2;
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
passportOAuth.Strategy.prototype.userProfile = function(accessToken, done) {
this._oauth2.get(constants.userRoute, accessToken, function(err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
try {
var json = JSON.parse(body);
OAuth.parseUserReturn(json, function(err, profile) {
if (err) return done(err);
profile.provider = constants.name;
done(null, profile);
});
} catch(e) {
done(e);
}
});
};
}
opts.passReqToCallback = true;
passport.use(constants.name, new passportOAuth(opts, function(req, token, secret, profile, done) {
OAuth.login({
oAuthid: profile.id,
handle: profile.displayName,
email: profile.emails[0].value,
isAdmin: profile.isAdmin
}, function(err, user) {
if (err) {
return done(err);
}
authenticationController.onSuccessfulLogin(req, user.uid);
done(null, user);
});
}));
strategies.push({
name: constants.name,
url: '/auth/' + constants.name,
callbackURL: '/auth/' + constants.name + '/callback',
icon: 'fa-check-square',
scope: (constants.scope || '').split(',')
});
callback(null, strategies);
} else {
callback(new Error('OAuth Configuration is invalid'));
}
};
OAuth.parseUserReturn = function(data, callback) {
// Alter this section to include whatever data is necessary
// NodeBB *requires* the following: id, displayName, emails.
// Everything else is optional.
// Find out what is available by uncommenting this line:
// console.log(data);
var profile = {};
profile.id = data.id;
profile.displayName = data.name;
profile.emails = [{ value: data.email }];
// Do you want to automatically make somebody an admin? This line might help you do that...
// profile.isAdmin = data.isAdmin ? true : false;
// Delete or comment out the next TWO (2) lines when you are ready to proceed
process.stdout.write('===\nAt this point, you\'ll need to customise the above section to id, displayName, and emails into the "profile" object.\n===');
return callback(new Error('Congrats! So far so good -- please see server log for details'));
callback(null, profile);
}
OAuth.login = function(payload, callback) {
OAuth.getUidByOAuthid(payload.oAuthid, function(err, uid) {
if(err) {
return callback(err);
}
if (uid !== null) {
// Existing User
callback(null, {
uid: uid
});
} else {
// New User
var success = function(uid) {
// Save provider-specific information to the user
User.setUserField(uid, constants.name + 'Id', payload.oAuthid);
db.setObjectField(constants.name + 'Id:uid', payload.oAuthid, uid);
if (payload.isAdmin) {
Groups.join('administrators', uid, function(err) {
callback(null, {
uid: uid
});
});
} else {
callback(null, {
uid: uid
});
}
};
User.getUidByEmail(payload.email, function(err, uid) {
if(err) {
return callback(err);
}
if (!uid) {
User.create({
username: payload.handle,
email: payload.email
}, function(err, uid) {
if(err) {
return callback(err);
}
success(uid);
});
} else {
success(uid); // Existing account -- merge
}
});
}
});
};
OAuth.getUidByOAuthid = function(oAuthid, callback) {
db.getObjectField(constants.name + 'Id:uid', oAuthid, function(err, uid) {
if (err) {
return callback(err);
}
callback(null, uid);
});
};
OAuth.deleteUserData = function(data, callback) {
async.waterfall([
async.apply(User.getUserField, data.uid, constants.name + 'Id'),
function(oAuthIdToDelete, next) {
db.deleteObjectField(constants.name + 'Id:uid', oAuthIdToDelete, next);
}
], function(err) {
if (err) {
winston.error('[sso-oauth] Could not remove OAuthId data for uid ' + data.uid + '. Error: ' + err);
return callback(err);
}
callback(null, data);
});
};
module.exports = OAuth;
}(module));
根据我对其工作原理的理解:nodebb调用我的授权端点并检查客户端是否正确并为其授予访问代码,然后访问我的令牌端点并交换此访问代码以获取令牌。我把它带到用户端点并交给我的用户凭据登录。我认为我错了,因为它不起作用我认为问题可能来自名称:create-and-login-user我正在使用但我不知道如何改进我上面编写的代码。
我不清楚回调uri的作用是什么,为什么名称回调被附加到它以及是否必须在我的应用程序上有这个url的端点。
好的,我取得了一些进展,但我遇到了这个错误:
https://www.dropbox.com/s/hm711i99iex4v1x/Screenshot%202017-02-13%2021.57.07.png?dl=0
它与回调uri有关。我应该为它提供一个端点,如果是,为什么它不指向我的应用端口号,而是指向nodebb