SSO单点登录实现方案

最近打算做个项目,需要用到单点登录,搜了看了一下资料找到一种单点登录方案,特此记录。

一、实现原理

        将登录系统单独摘出来,做成一个登录子系统。请求登陆时候访问这个子系统,当登陆验证通过的时候,生成一个token存入网站顶级域名下的cookie当中。将与这个token对应的用户状态信息存入缓存中去,并设置生存时间,此处缓存使用的是redis。当其他的子系访问必须登录才可访问的资源时候,必须先到登录系统进行验证token的存在性以及是否过期,验证通过才可进行访问。

      具体流程:(侵权删除)

 

二、重要的地方:

                (1)cookie保存在一级域名下面(我叫做根域名):比如:对于百度,baidu.com就是一级域名,而www.baidu.com或者zhidao.baidu.com这样的域名都是二级域名,而我们可以从二级域名下访问一级域名的cookie。这样我们就可以访问保存到本地的token

            (2)token:这相当于一个令牌,不管你在哪个子系统下面,想要获取登陆状态就需要获得单点登录系统生成的token,这个token是在登陆成功时候生成,生成后保存到redis(缓存)中作为key,key生成规则使用的是UUID,目的是为了防止多个用户登录时候产生冲突,value为用户的信息,并设置有效时间。同时将这个key保存到cookie当中。这样当你需要验证登录状态的时候,只需要取出这个token并去缓存中查询是否存在相应数据,如果存在,就说明是在登陆状态。如果token存在而缓存中不存在说明用户登录状态过期了。如果没有token,说明用户根本没有登录。

三、具体的实现

             核心部分的代码:其中Result保存处理的结果。

  UserServiceImpl:

                   

        //根据用户的用户名密码查询信息
        User temp=userMapper.findByUsernameAndPassword(user);

        //如果用户名密码正确会查询出信息,不对的话无法查询到
        if(temp==null){
            return Result.build(400,"用户名或密码不正确");
        }
        //查询到的话生成token作为键,用户的信息作为值保存到redis中
        String token_ID=UUID.randomUUID().toString().replaceAll("-","");
        temp.setPassword(null);
        jedis.set(TOKEN_ID+":"+token_ID, JsonUtils.objectToJson(temp));
        jedis.expire(TOKEN_ID+":"+token_ID,300);
        //返回给controller层,并从controller层中将token保存到根cookie中
        return Result.ok(token_ID);

     UserController:

        //从service层获取信息,如果登陆成功里面会保存有token
        Result result= this.userService.login(user);
        //将cookie写入本地根域名下面
        if (result.getStatus().equals(200)){
            CookiteUtils.setCookie(request,response,TOKEN_ID,result.getMsg());
        }
        return  result;

四、其他系统调用sso系统

            我设计的是user子系统,里面只有一个登录状态的检测功能。User子系统中通过ajax异步发送信息,调用sso系统的代码进行登录状态的检测,并将数据返回给调用处。但是由于js无法跨域请求数据,所以使用了jsonp(不懂的话百度一下这方面的知识)。大体意思不能通过js跨域请求数据,但可以跨域请求js函数或js文件。

         

    //跨域请求,使用jsonp
    $.ajax({
        type:"GET",
        dataType:"jsonp",
        url:"http://localhost:8080/user/token/"+_ticket,
        success: function (data) {
            //登录成功显示用户名
                if (data.status==200){
                    var username=data.data.username;
                    var html=username;
                    $("#checkLogin").html(html);
                }
        }
    });

 

 

具体代码放在我的github https://github.com/GregZQ/sso

 

ps:如果有不正确的地方请各位提出指正,谢谢。

         

posted @ 2018-01-27 21:50  十禾。  阅读(1100)  评论(0编辑  收藏  举报