认证中心:基于cookie和session实现单点登陆

流程图

在这里插入图片描述

参数

不同域名之下(不同父域名)
cookie+session+redis

流程追踪

用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

sso认证中心发现用户未登录,将用户引导至登录页面

用户输入用户名密码提交登录申请s

so认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌。

//client携带redirect_url来这里请求我们的认证
    //那么需要再认证页面上保存下来redirect_url
    //@CookieValue(value = "sso_token", required = false)
    @GetMapping("/login.html")
    public String loginPage(@RequestParam("redirect_url") String url, Model model, @CookieValue(value = "sso_token", required = false) String sso_token) {
        //如果存在sso_token
        if (!StringUtils.isEmpty(sso_token)) {
            return "redirect:" + url + "?token=" + sso_token;
        }
        //知道下个页面跳转的位置
        model.addAttribute("url", url);
        return "login";
    }

    @ResponseBody
    @GetMapping("/userinfo")
    public String userinfo(@RequestParam(value = "token") String token) {
        String s = stringRedisTemplate.opsForValue().get(token);
        return s;
    }

    @PostMapping("/doLogin")
    public String doLogin(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("redirect_url") String url, HttpServletResponse response) {
        //如果想要退出登录那么sso_token失效
        if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
            //颁发token 并且将信息存放到redis中
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            stringRedisTemplate.opsForValue().set(uuid,username);
            //向客户端浏览器写入token
            Cookie cookie = new Cookie("sso_token",uuid);
            response.addCookie(cookie);
            //将cookie写到浏览器
            //原因是如果第一个服务已经登录,第二个服务来登录,检测到没有session没有token来进行认证
            //login检测到cookie中有登录状态就应该通过
            return "redirect:" + url + "?token=" + uuid;
        }
        return "login";
    }

sso认证中心带着令牌跳转会最初的请求地址(系统1)

系统1拿到令牌,去sso认证中心校验令牌是否有效

sso认证中心校验令牌,返回有效,注册系统1

系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源

    @GetMapping(value = "/employees")
    public String employees(Model model, HttpSession session, @RequestParam(value = "token", required = false) String token) {
        //如果token存在
        if (!StringUtils.isEmpty(token)) {
            RestTemplate restTemplate = new RestTemplate();
            //根据token获取其中的用户信息放到session当中
            ResponseEntity<String> forEntity = restTemplate.getForEntity("http://ssoserver.com:8080/userinfo?token=" + token, String.class);
            String body = forEntity.getBody();

            session.setAttribute("loginUser", body);
        }
        //session是否存在
        Object user = session.getAttribute("loginUser");
        if (user == null) {
            //进入认证中心进行登录 并且指定登录成功之后的重定向页面
            return "redirect:" + "http://ssoserver.com:8080/login.html" + "?redirect_url=http://client1.com:8082/employees";
        } else {
            //返回信息
            List<String> res = new ArrayList<>();
            res.add("张三");
            res.add("李四");
            model.addAttribute("emps", res);
            return "employees";
        }
    }

用户访问系统2的受保护资源

系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌

系统2拿到令牌,去sso认证中心校验令牌是否有效

sso认证中心校验令牌,返回有效,注册系统2

系统2使用该令牌创建与用户的局部会话,返回受保护资源用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话

用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心

分析

每个系统中都会存在一份cookie,并且在第一次登录的时候系统要去访问用户中心获取令牌,之后就是session。
当用户退出系统,需要做的是销毁局部会话以及cookie,重定向到认证中心的退出接口,认证中心从会话中获取令牌,销毁全局会话,清除redis中该token的用户信息,调用缓存中系统的退出接口,清除每个客户端的局部会话,接着跳转登录页面。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值