nodeclub icon indicating copy to clipboard operation
nodeclub copied to clipboard

账号同步问题

Open liangdas opened this issue 9 years ago • 11 comments

我想将这个系统用于我们现在的网站,但用户直接用我们自己网站的,请问这个怎么做?

liangdas avatar Oct 14 '16 07:10 liangdas

我理解以下需求,你有一个网站,然后想用nodeclub做论坛,希望两个网站使用同一个账号系统

目前只能自己改造

TakWolf avatar Oct 14 '16 07:10 TakWolf

请问有改造的思路吗?

liangdas avatar Oct 14 '16 07:10 liangdas

简单的改造思路,网站端跟论坛端是两套独立的用户系统,论坛账号创建的时候,需要绑定一个网站端账号。这样两套系统大体是还是独立的,耦合较小

非要强制用一套账号,那改的就多了

TakWolf avatar Oct 14 '16 07:10 TakWolf

就您刚才说的那套方案就行,类似github登陆是吧?这个系统有对应的api吗?

liangdas avatar Oct 14 '16 08:10 liangdas

用SSO是一个思路,即单点登录。 改造方案简略:

  1. 原来网站继续账号创建啊,登录。
  2. 论坛登陆时,后台链接到原网站做认证,通过后保存并设置过期。
  3. 当session过期,重新定向到原网站做认证。

比如,淘宝的那些子服务,咸鱼啊支付宝都是同一个账户。

awong1900 avatar Oct 14 '16 08:10 awong1900

恩恩,我试试,现在我刚搭建起来,后台管理员页面怎么进?

liangdas avatar Oct 14 '16 08:10 liangdas

用SSO是一个思路 是不是就是目前系统里面github登陆的思路?

liangdas avatar Oct 14 '16 08:10 liangdas

那叫Oauth 不同的东西。 没有后台。 改什么直接改模版。

awong1900 avatar Oct 14 '16 09:10 awong1900

分析了一下大概知道怎么弄了,目前这个系统后台功能还比较缺乏,需要努力建设,很好的东西,非常感谢

liangdas avatar Oct 14 '16 10:10 liangdas

我直接共用cookie,读取主网站的session_id就可以了,然后在authUser这个拦截函数里面去主网站获取用户信息,这样这个系统就完全不需要外部登陆和注册了,我们主网站用的Python 今天第一次接触node.js

liangdas avatar Oct 14 '16 10:10 liangdas

下午研究改造集成了我们公司的单点登陆,加了一个 middleware,feature:

  • 如果未登陆,自动302跳转SSO LOGIN页面
  • SSO LOGIN登陆成功后,创建caToken, 跳转回来
  • 如果有caToken,但caToken对应的用户在nodeclub中不存在,则自动创建用户,自动创建session,并登陆
  • 如果有caToken,且caToken对应的用户在nodeclub中存在,但nodeclub session不存在,自动创建session,并登陆
  • 如果有caToken,且caToken对应的用户在nodeclub中存在,但nodeclub session存在,直接登陆

代码可以参见:

const request = require('request');
var Models = require('../models');
var User = Models.User;
var uuid = require('node-uuid');
var authMiddleWare = require('../middlewares/auth');
var config = require('../config');

const HOST_NAME = 'http://emp.cathay-ins.com.cn:8003';
const URL_REDIRECT_SSO_LOGIN = `${HOST_NAME}/sso/login?callback=http://club.cathay-ins.com.cn:3000`;


function relayCaToken(caToken, callback) {

    request({
        url: `${HOST_NAME}/api/sso/caToken/${caToken}`,
        method: 'PUT',
        json: true
    }, function (err, data, json) {

        console.log('request callback');

        console.log(err, json);

        callback(err, json);

    });

}


// 验证用户是否登录
module.exports = function (req, res, next) {


    let caToken = req.cookies['caToken'];


    // SSO没有登陆
    if (!caToken) {
        res.redirect(URL_REDIRECT_SSO_LOGIN);
        console.log('sso not login')
        return;
    }

    function getName(ssoUser) {

        return ssoUser.nickName || (ssoUser.name + '_' + ssoUser.ID);

    }

    relayCaToken(caToken, function (err, result) {

        // sso是否登陆
        if (result) {

            let userInfo = result.userInfo;

            // 判断用户是否存在
            User.findOne({loginname: getName(userInfo)}, function (err, user) {

                // 不存在,则创建用户
                if (!user) {
                    console.log('用户不存在,开始创建');
                    createUser(userInfo);
                } else {
                    console.log('用户存在', user);
                    // 用户存在,则检查cookie
                    var auth_token = req.signedCookies[config.auth_cookie_name];

                    // session过期,重新生成session, 刷新页面
                    if (!auth_token) {
                        authMiddleWare.gen_session(user, res);
                        res.redirect('/');
                        return;
                    }
                    req.session.user = user;

                    next();
                }

            });
        } else {

            // sso登陆过期
            res.redirect(URL_REDIRECT_SSO_LOGIN);
            console.log('sso timeout');
            return;
        }


    });

    function createUser(ssoUser) {
        var user = new User({
            loginname: getName(ssoUser),
            pass: 'Cathay1234Random',
            email: ssoUser.email,
            active: true,
            accessToken: uuid.v4(),
        });

        user.save(function (err) {

            console.log(err);

            if (err) {
                console.log('创建用户失败', err);
                // 根据 err.err 的错误信息决定如何回应用户,这个地方写得很难看
                if (err.message.indexOf('duplicate key error') !== -1) {
                    if (err.message.indexOf('email') !== -1) {
                        return res.status(500)
                            .send('关联失败,邮箱重复');
                    }
                    if (err.message.indexOf('loginname') !== -1) {
                        return res.status(500)
                            .send('关联失败,账号重复');
                    }
                }
                return next(err);
                // END 根据 err.err 的错误信息决定如何回应用户,这个地方写得很难看
            }

            console.log('创建用户成功');

            authMiddleWare.gen_session(user, res);
            res.redirect('/');

            return;
        });
    }


};

johnnychq avatar May 18 '17 13:05 johnnychq