V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
a623397674
V2EX  ›  程序员

关于 sso 项目

  •  
  •   a623397674 · 2018-10-23 18:27:04 +08:00 · 945 次点击
    这是一个创建于 1983 天前的主题,其中的信息可能已经有所发展或是发生改变。
    关于一个用过的 sso 项目:
    这个项目因为是第一次接触,以为 sso 项目就是这个样子:
    使用框架技术:
    springMVC,mybitas,redis,dubbo,zookerper
    主要功能:
    用户登录 /注册(第三方登录 /注册),用户注销,用户验证(用于分布式切面类)
    前两个功能,就不详细说了“注册和登录时一个接口,就是查询数据库中是否有第三方的 id,数据库没有就生成三个表( three_id ),( user_id )-(account_id),( id,token )”
    重点说第三个:用户验证,用户验证是提供给其他服务消费方用的,项目中使用的是 dubbo 分布式,所以就把验证写成接口形式。需要调用的服务( controller )中,写了一个 aop,验证用户是否登录,就是调用这个代码,然后继续执行,否者就返回异常。

    因为是数据库查询慢,所以又加了一个缓存,就是吧验证信息,和用户信息放在了 redis 一份。
    公司是做移动端对接的,一开始设计并没有包含 web 端,后来 web 端也是我写的,接口没动,只是把 token 在 web 登录之后手动保存在客户端,不同域名下访问做了 nginx 的接口过滤。
    为什么要拿出来说一下呢,是因为去面试他让我说 sso 单点的 cookie,他说服务端怎么放 cookie,我说服务端放 redis,不管客户端 cookie 怎么放,不只是误解,还是理解不对,面试官对此回答不满意,所以我就注意到了这个事情,所以之后就看一些文章:
    1、单台的 web 是用 session 的,客户端和服务端的 session 是共享的,所以 jsp 和服务端中读写 session 可以有效验证(都用过)
    2、到分布式的时候,遇到多服务器 session 不一致,可以用 tomcat 的广播组同步 session,也可以解决(没有验证)
    3、就是设置项目中的 redissession,这个是 spring 的一个组件(我统称为 spring 的技术为组件,不知道有没有什么问题),具体没用过,内部 redis 的 session 管理机制可以理解
    起初我是觉得我的 sso 项目是第三者模式。可是,偶尔跟同学(也是同行),他说他用的就是第三者模式,但是会用到 session,会有一个用户会话的东西,第一次验证之后,建立 session,以后就不用验证了。
    问题来了: 在我 debug 的时候,而我的项目是每次都过验证的( aop ),也就是说每次都用验证,所以,好像我的是一个假的单点登录,而是每次的令牌验证?
    所以,我想问一下大牛们,sso 单点登录项目,原理和最完善的原理模式是什么,我司的这个 sso 项目,是不是一个真正意义上的单点登录。
    顺便献上 aop 验证的那段代码:


    public String checkToken(ProceedingJoinPoint pjp, CheckToken checkToken) throws Throwable {
    // 获取 request 属性
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    try {
    // 从 header 中获取要校验的参数
    CheckUserParam param = new CheckUserParam();
    RequestHeaderToolkit.createSsoParam(request, param);

    // 打印入参
    if(log.isInfoEnabled())
    log.info("CheckTokenAspect/checkToken,parram={}", JSONObject.toJSONString(param));

    // 先从缓存中取出合适的数据 TODO

    // 缓存中没有,调用 dubbo 接口
    CheckUserResult rtn = ssoInterface.checkUser(param);

    // 返回有异常,直接抛出异常
    if(rtn.getRetCode() != 0) {
    log.error("校验用户,发生异常: parram={},rtn="+rtn.getRetCode() ,JSONObject.toJSONString(param));
    Map<String, Object> map=new HashMap<String, Object>();
    map.put("retCode", rtn.getRetCode());
    map.put("msg", rtn.getMsg());
    return JSON.toJSONString(map);
    }

    // 如果不允许匿名登录,则抛出异常
    if(!checkToken.allowGuest() && ( StringUtils.isBlank(rtn.getUserRole()) || RoleEnum.GUEST.name().equals(rtn.getUserRole()))) {
    log.error("不允许匿名登录,parram={}" ,JSONObject.toJSONString(param));
    Map<String, Object> map=new HashMap<String, Object>();
    map.put("retCode", WirelessErrorEnum.PLEASE_LOGIN_PARAM_ERROR.getCode());
    map.put("msg", WirelessErrorEnum.PLEASE_LOGIN_PARAM_ERROR.getMessage());
    return JSON.toJSONString(map);
    }

    // 构造返回值
    request.setAttribute(StaticFinalAppId.userId, String.valueOf(rtn.getUserId())); // 登录用户 id 未登录用不送或送 0
    request.setAttribute(StaticFinalAppId.userRole, rtn.getUserRole()); // 登录用户 id 未登录用不送或送 0
    request.setAttribute(StaticFinalAppId.chatPassword, rtn.getChatPassword()); // 登录聊天室时使用的密码

    // 继续执行方法
    return (String)pjp.proceed();
    } catch (RuntimeException e) {
    log.error("校验用户信息时,发生异常," + e.getMessage() ,e);
    Map<String, Object> map=new HashMap<String, Object>();
    map.put("retCode", -1);
    map.put("msg", "An error occurred, please contact customer service.(-1)");
    return JSON.toJSONString(map);
    }
    }
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1200 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 23:13 · PVG 07:13 · LAX 16:13 · JFK 19:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.