• B
    brucehuang

    我用了很山寨的方法,延迟发送login。setTimeout(function(){$.ajax('/login', {...})}), 2000)。
    谢谢你的提醒,我去看看nodebb-plugin-session-sharing 这个插件:blush:

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    根据我打日志,其实还是走了onSuccessfulLogin 的,会从自定义的continueLogin 跳回到 authenticationController.continueLogin去。

    他的流程是这样的,有点绕。
    ajax login -> authenticationController.login -> authenticationController.continueLogin -> 自定义的continueLogin -> 回到authenticationController.continueLogin -> authenticationController.doLogin -> authenticationController.onSuccessfulLogin

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    设置了cookie寿命还是一样。

    不过我倒是想到另一件事,是否是并发请求导致的?

    在正常登录状态,不会有跟login并发的请求,后台也就不会有session互相覆盖的情况。
    而通过sso.js注入的ajax login请求是跟页面中其他url请求一起到后台的,所以容易造成在后台竞争态导致互相覆盖(nodebb后台并没有按做条件更新而是直接全量覆盖)。

    所以解决办法应该是在后台增加条件更新(如果有passport则不覆盖,只更新其他字段)或者在client端延迟发送login。

    我增加setTimeout函数延迟发送ajax login请求,试验了几次观察后台日志貌似消除了竞争态,我再观察一下:)

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    站长你好,代码如下:
    (function (module) {
    "use strict";

    var passport = module.parent.require('passport'),
    passportLocal = module.parent.require('passport-local').Strategy,
    User = module.parent.require('./user'),
    Groups = module.parent.require('./groups'),
    meta = module.parent.require('./meta'),
    db = module.parent.require('../src/database'),
    fs = module.parent.require('fs'),
    path = module.parent.require('path'),
    nconf = module.parent.require('nconf'),
    winston = module.parent.require('winston'),
    async = module.parent.require('async'),
    request = require('request'),
    constants = Object.freeze({
    		name: 'MyID'
    	}),
    plugin = {};
    
    plugin.login = function () {
    	winston.info('[login] Registering new local login strategy');
    	passport.use(new passportLocal({
    			passReqToCallback: true
    		}, plugin.continueLogin));
    };
    
    plugin.continueLogin = function (req, username, password, next) {	
    	var userToken = username;
    	if (typeof(userToken) == 'undefined') {
    		winston.info('cookie userToken undefined');
    		return next(new Error('[[error:invalid-username-or-password]]'));
    	}
    	request('http://www.myDomain.cn/api/user/' + userToken,
    		function (err, response, body) {
    		if (err) {
    			winston.error(err);
    			return next(null, null);
    		}
    
    		if (response.statusCode === 200) 
    		{
    			if (body=='null' || typeof(body) == 'undefined')
    			{
    				return next(new Error('[[error:invalid-token1]]'));
    			}
    			var data = JSON.parse(body);
    			var userinfo = {};
    			userinfo.Id = data.Id;
    			userinfo.username = data.NickName;
    			userinfo.email = data.NickName + '@myDomain.cn';
    
    			userinfo.picture = 'https://www.myDomain.cn/' + data.image;
    			
    			userinfo.isAdmin = data.isAdmin;
    			
    			plugin.moreLogin(userinfo,
    				function (err, user) {
    					if (err) 
    					{
    						return next(err);
    					}
    					next(null, user);
    				});
    		}
    		else
    		{
    			next(new Error('[[error:internal-error]]'))
    		}
    	});
    };
    
    plugin.getUidByMyId = function (myid, callback) {
    	db.getObjectField(constants.name + 'Id:uid', myid, function (err, uid) {
    		if (err) {
    			return callback(err);
    		}
    		callback(null, uid);
    	});
    };
    
    plugin.moreLogin = function (userinfo, callback) {
    	if (userinfo) 
    	{
    		plugin.getUidByMyId(userinfo.Id, function (err, uid) {
    			if (err) 
    			{
    				return callback(err);
    			}
    
    			if (uid !== null) 
    			{					
    				// Existing User, update profile
    				var data = 
    				{
    					uid: uid,
    					username: userinfo.username,
    					email: userinfo.email,
    				};
    				
    				//update profile
    				User.getUserField(uid, 'username', function (err, oldUserName){
    					if (oldUserName != userinfo.username)
    					{
    						User.updateProfile(uid, data, function(err){
    							if (err)
    							{
    								winston.info('uid:' + uid + ' updateprofile err=' + err);
    								return callback(null, {uid: uid});
    							}
    							else
    							{
    								User.setUserField( uid, 'picture', userinfo.picture );
    								if (userinfo.isAdmin == '1') 
    								{
    									Groups.join('administrators', uid, function (err){return callback(null, {uid: uid});});
    								}
    								else
    								{
    									callback(null, {uid: uid});
    								}
    							}
    						});
    					}
    					else
    					{
    						callback(null, {uid: uid});
    					}
    				});
    			}
    			else 
    			{
    				var success = function (uid) {
    					// Save provider-specific information to the user
    					User.setUserField(uid, constants.name + 'Id', userinfo.Id);
    					db.setObjectField(constants.name + 'Id:uid', userinfo.Id, uid);
    
    					if (userinfo.picture) 
    					{
    						var picture = userinfo.picture;
    						User.setUserField(uid, 'picture', picture);
    					}
    
    					if (userinfo.isAdmin == '1') 
    					{
    						Groups.join('administrators', uid, function (err) {
    							winston.info('join administrators err ' + err + ' uid=' + uid);
    							callback(null, {uid: uid});
    						});
    					} 
    					else 
    					{
    						callback(null, {uid: uid});
    					}
    				};
    
    				if (! uid) 
    				{
    					User.create(
    					{
    						username: userinfo.username,
    						email: userinfo.email
    					}, function (err, uid) {
    						if (err) 
    						{ 
    							winston.info(err);
    							return callback(err);
    						}
    						success(uid);
    					});
    				}
    				else 
    				{
    					success(uid); // Existing account -- merge
    				}
    			}
    		});
    	}
    	else 
    	{
    		winston.error('[missing UserInfo]');
    		if (callback) {	callback(new Error('[[error:missing-UserInfo]]'));}
    	}
    };
    

    module.exports = plugin;
    }(module));

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    版主你好。我用的是这种方式,https://github.com/contentblvd/nodebb-plugin-sso-session/blob/master/library.js
    重写了continueLogin,逻辑写在request的回调中。
    request('http://mydomain.com/users/' + userToken, function (err, response, body) {xxx})。

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    回调只有一个,我在sso.js的代码是这样的:
    $.ajax('/login', {
    type: 'POST',
    data: 'username=' + userToken + '&password=' + new Date().getTime(),
    headers: {
    'x-csrf-token': config.csrf_token
    },
    success: function () {window.location.href = currentURL;});

    但在后台,login后面请求的url会覆盖login产生的session,比如在下面的截图中,/src/client/chats/recent.js?v=c18e8ec4-2fb9-48f9-83b1-4b650f4d818a产生的没有passport的session覆盖了login产生的有passport的sessio。

    0_1484014995444_无标题.png

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    参考nodebb-plugin-sso-session写了个sso登录插件,但出现了些问题,表现在主站登录后并没有在nodebb登录成功,有时十几次出现一次,有时候频繁出现。在nodebb中打日志发现登录不了的时候有以下现象:

    1. 从主站同步数据成功,处理完continueLogin函数,来到src/controllersauthentication.js中的authenticationController.onSuccessfulLogin(),这时生成了req.session.passport:
      10/1 09:21:27 [37124] - info: onSuccessLogIn sessionId=gjeFe8KsBiXlbbPkEMgnHxrD1l_KPzb1 req.session={"cookie":{"originalMaxAge":1209600000,"expires":"2017-01-24T01:21:27.133Z","httpOnly":true,"domain":".mydomain.cn","path":"/"},"csrfSecret":"SgW2ayatX0nQMhvStH_jan2T","passport":{"user":6},"meta":{"ip":"127.0.0.1","uuid":"42cea1ef-2f58-417f-a31e-c9fb8cb8f8d6","datetime":1484011287135,"platform":"Microsoft Windows","browser":"Chrome","version":"54.0.2840.71"}}

    2. 但session还没保存时,另一个url的请求进来了,这时req.session是没有passport的:
      node_modules\passport\lib\middleware\initialize.js中的function initialize(passport):
      10/1 09:21:27 [37124] - info: passport initialize url=/vendor/jquery/timeago/locales/jquery.timeago.zh-CN.js?_=1484011286686 req from 127.0.0.1 session={"cookie":{"originalMaxAge":1209599999,"expires":"2017-01-24T01:21:27.070Z","httpOnly":true,"domain":".mydomain.cn","path":"/"},"csrfSecret":"SgW2ayatX0nQMhvStH_jan2T"}

    1. login保存session:
      node_modules\express-session\index.js中的req.session.save(function onsave(err)) :
      10/1 09:21:27 [37124] - info: express-session session.save onsave url=/login {"cookie":{"originalMaxAge":1209600000,"expires":"2017-01-24T01:21:27.148Z","httpOnly":true,"domain":".mydomain.cn","path":"/"},"csrfSecret":"SgW2ayatX0nQMhvStH_jan2T","passport":{"user":6},"meta":{"ip":"127.0.0.1","uuid":"42cea1ef-2f58-417f-a31e-c9fb8cb8f8d6","datetime":1484011287135,"platform":"Microsoft Windows","browser":"Chrome","version":"54.0.2840.71"}} err=null

    2. url=/vendor/jquery/timeago/locales/jquery.timeago.zh-CN.js?=1484011286686 保存session:
      node_modules\express-session\index.js中的req.session.save(function onsave(err)) :
      10/1 09:21:27 [37124] - info: express-session session.save onsave url=/vendor/jquery/timeago/locales/jquery.timeago.zh-CN.js?
      =1484011286686 {"cookie":{"originalMaxAge":1209599999,"expires":"2017-01-24T01:21:27.143Z","httpOnly":true,"domain":".mydomain.cn","path":"/"},"csrfSecret":"SgW2ayatX0nQMhvStH_jan2T"} err=null

    导致了login产生的passport被覆盖,登录不成功。
    关闭自定义的sso,用nodebb自带的登录界面,则不会出现这样交叉的情况。没想清楚原因。请版主指点指点:)

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    兜了一个大圈,终于搞定了,自行做个总结,在启动论坛前运行命令nodebb build即可。
    感谢river兄的热心帮助:-)

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    @river ,学习了。我刚才看了下,代码没有注入到nodebb.min.js中。我再查查咋回事。谢谢你:-)

    发布在 NodeBB 阅读更多
  • B
    brucehuang

    @river 还得请教个问题。我已经安装好了这个插件https://github.com/contentblvd/nodebb-plugin-sso-session,continueLogin的hook生效了。但是注入前端的sso.js未发现生效。在入口处打了alert('xxx'),没有弹出信息。是我用得有问题吗?

    发布在 NodeBB 阅读更多

与 V2MM 的连接断开,我们正在尝试重连,请耐心等待