httpsession cookie 单点登录 顶域

在大部分时候,我们在讨论API的设计时,会从功能的角度出发定义出完善的、易用的API。而很多时候,非功能需求如安全需求则会在很晚才加入考虑。而往往这部分会涉及很多额外的工作量,比如与外部的SSO集成,Token机制等等。对该安全需求,一般有如下方案:

• 基于session的认证鉴权

• 基于token的认证鉴权

基于session

由于HTTP协议本身是无状态的,服务器需要某种机制来区分每个请求。比如在返回给客户端的响应中加入一些ID,客户端再次请求时带上这个ID,这样服务器就可以区分出来每个请求,并完成后续事务性的操作。在传统的Web容器中,这种机制通过Session来实现。Web容器会为每个首次请求创建一个Session,并将SessionID以浏览器Cookie的方式返回给客户端。客户端(常常是浏览器)在后续的请求中带上这个SessionID来表明自己的身份。这种机制同样被用在了鉴权方面,用户登录系统之后,系统分配一个SessionID给它。除非Session过期,或者用户从客户端的Cookie中主动删了SessionID,否则在服务器端看来,用户的信息会和这个Session绑定起来。后台系统也可以随时知道请求某个资源的真实用户是谁,并以此来判断该用户时候真的有权限这么做。

Session的问题及解决方案

这种做法在小规模应用中工作良好,但是随着用户的增多,企业往往需要部署多台服务器形成集群来对外提供服务。在集群模式下,当某个节点挂掉之后,由于Session默认是保存在部署Web容器中的,用户会被误判为未登录,后续的请求会被重定向到登陆页面,影响用户体验。这种将应用程序状态内置的方法已经完全无法满足应用的扩展,因此在工程实践中,我们会采用将Session外置的方式来解决这个问题。即集群中的所有节点都将Session保存在一个公用的键值数据库中。典型的做法就是使用spring session,将原来保存在各服务实例中的 Session 保存到实例共享的同一存储介质中。这样的话,无论请求访问到哪个服务实例,Session 均会对共享存储进行读写,从而达到 Session 共享的目的。目前常用Hazelcast和Redis作为存储session的介质,spring session官方文档对此有详细介绍:https://docs.spring.io/spring-session/docs/current/reference/html5/guides/hazelcast-spring.html和https://docs.spring.io/spring-session/docs/current/reference/html5/guides/security.html 采用外置的方式(比如Redis),Spring会拦截所有对HTTPSession对象的操作,后续的对Session的操作,Spring都会自动转换为与后台的Redis服务器的交互,从而避免节点挂掉之后Session丢失的问题。

基于token的认证鉴权

一般认为基于OAuth和JWT方案都是基于Token的,但OAuth对于不做开放平台的公司有些过于复杂。这里所说基于token的认证鉴权主要指JWT。
微信OAUTH2文章!!!!!!

微信2!!!!!!

下面简单以接入微博开放平台为例
在这里插入图片描述
微博回调地址 跳转回来会携带code
就是一个访问服务器的请求 我们只要在本地写一个controller就能将code获取

如果本次会话的session里没有当前这个loginuser的记录 说明没登陆过
在这里插入图片描述

一个域名下的不同微服务共享会话+一个微服务集群不同服务器共享会话

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面这个hash应该是sessionID
在这里插入图片描述
MapSession中持有HashMap类型的变量sessionAtts用于存储Session设置属性,比如调用的setAttribute方法的k-v就存储在该HashMap中。这个和tomcat内部实现HttpSession的方式类似,tomcat中使用了ConcurrentHashMap存储。

其中lastAccessedTime用于记录最近的一次访问时间,maxInactiveInterval用于记录Session的最大闲置时间(过期时间-针对没有Request活跃的情况下的最大时间,即相对于最近一次访问后的最大闲置时间)。
在这里插入图片描述
cookie name 为jsessionid value 为sessionid
请求到服务器时 根据value去查找具体的session
根据session去
https://www.cnblogs.com/lxyit/p/9672097.html

cookie是服务器发送回来的
在一个大业务下比如gulimall.com 是顶域 它下面的其他微服务 比如 auth.gulimall.com 是子域 即使cookie此时已经跨域 我们可以通过服务器代码设置让cookie 的domain 永远是在顶域的 这样就可以做到 访问这些网址的时候 cookie的jessionid名字都相同

单点登录111

filter 实现222

333333333
但是当跨系统 如果已经不在gulimall.com 下的子域 而是在其他的系统比如 taobao.com 现在已经不是顶域可以解决的了
cookie已经势必会改变 怎么做到顶域不同也能cookie的jsessionid相同(即还是那个cookie)
我们使用第三个系统 sso系统 所有人的登陆 都不是在请求自己服务登陆 而是请求到sso 在sso里面登陆 请求的是sso网址
注意 请求什么网址 一个cookie 是在该网址下面对一一应存储的
sso把seesion 和 cookie 存储了
当其他系统也要登陆的时候 先是直接跳到sso 在sso中把cookie当作一个sT传递给请求的系统
在这里插入图片描述
登陆client网站 的代码逻辑
第二次登陆 把本次请求的seesion token 拿到 去sso server中心去找当前这个token /cookie对应的redis中的vo数据 把封装的用户信息loginUser放到本次client请求的session 中 当前网站就有了登陆权限可以看到下面 张三 李四 这些数据了

第一次登陆 token是空的 vo数据是空的 那就重定向到sso server的登陆页面去登陆
然后sso server跳转回当前方法 此时token 已经不是空的了 就可以在本次会话session里放上值了 于是session就知道客户端是谁 换句话就登陆成功了

先把是否有token 放前面做防御

@GetMapping(value = "/employees")
    public String employees(Model model, HttpSession session, @RequestParam(value = "token", required = false) String token) {

        if (!StringUtils.isEmpty(token)) {
            RestTemplate restTemplate=new RestTemplate();
            ResponseEntity<String> forEntity = restTemplate.getForEntity("http://sso.mroldx.cn:8080/userinfo?token=" + token, String.class);
            String body = forEntity.getBody();

            session.setAttribute("loginUser", body);
        }
        Object loginUser = session.getAttribute("loginUser");

        if (loginUser == null) {

            return "redirect:" + "http://sso.mroldx.cn:8080/login.html"+"?redirect_url=http://localhost:8081/employees";
        } else {


            List<String> emps = new ArrayList<>();

            emps.add("张三");
            emps.add("李四");

            model.addAttribute("emps", emps);
            return "employees";
        }
    }

sso server中心的代码
第一次从别的网站过来登陆 要将当前的cookie 与 session 绑定
给当前的请求cookie 命名为sso_token 对应的jessionId 是随机的uuid

sso 服务器这边存在session 里的k-v 是uuid -保存的UserName
这样就可以cookie一来就获得当前的用户名

然后把这个session 放到redis中外置保存

最后跳转回原始的网站 并且把这个cookie的uuid 返回到client服务器 就好像微博开放平台返回给我们一个Code 一样
sso server返回给client服务器当前这个浏览器的这个cookie(sso_token)的专属token 服务器拿到这个code 之后就可以直接向sso server的redis中请求user name 了

    @PostMapping(value = "/doLogin")
    public String doLogin(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("redirect_url") String url, HttpServletResponse response) {

        //登录成功跳转,跳回到登录页
        if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {

            String uuid = UUID.randomUUID().toString().replace("_", "");
            redisTemplate.opsForValue().set(uuid, username);
            Cookie sso_token = new Cookie("sso_token", uuid);

            response.addCookie(sso_token);
            return "redirect:" + url + "?token=" + uuid;
        }
        return "login";
    }

在这里插入图片描述
访问其中一个系统的网站
在这里插入图片描述
由于没有登陆过 先看是否有token 没有 说明也没在sso 中登陆过
重定向到sso 进行登陆 并且重定向的url中还包含从哪里调转过来
在这里插入图片描述
开始登陆 登陆成功之后 给浏览器端保留一个cookie (名字sso_token ) jessionid为随机的uuid
以后再登陆 就携带这个cookie跳转到sso server了 根据所保存的jsessionid 查找到session 红保存的username
在这里插入图片描述
在这里插入图片描述
以后只要是访问sso.com 这个域名 cookie 肯定就是uuid 了
在这里插入图片描述
uuid 是具体的值 这里是为了演示含义
真实的是下面这样的
在这里插入图片描述
set-cookie 是让浏览器执行的动作
在这里插入图片描述
当第二个系统也要登陆的时候 还是重定向到sso 的login 但是按照之前的逻辑 此时还没有token 因为没有登陆过 还是要输入账户和密码 我们就让login写上如果你是别的新的系统 过来没有经历上面这一长串 你也不用经历了 只要sso server域名下已经有cookie 了就不用再经历了 直接跳回就行

@GetMapping("/login.html")
    public String loginPage(@RequestParam("redirect_url") String url, Model model, @CookieValue(value = "sso_token", required = false) String sso_token) {
        if (!StringUtils.isEmpty(sso_token)) {
            return "redirect:" + url + "?token=" + sso_token;
        }
        model.addAttribute("url", url);
        return "login";
    }

单点登录 当时在想 是啊 如果都到顶域了 cookie 没有办法彼此共享 不同的系统怎么使用相同的cookie啊 以为会做什么让大家各自的系统cookie统一
其实不用 单点登录 是引入了第三方的系统 大家都去第三方系统登陆 肯定能保证在使用同一个cookie session 也共享了

那要想做到共享 就要首先重定向到sso server 登陆完 在sso.com的域名下 保留cookie 再重定向回访问的系统 根据返回的url携带的uuid获得保存的数据vo
然后就顺利的登陆上了
之后再登陆的话 也是 根据token 即 jessionid 去sso 找到redis 中存储的对应的 user 然后返回就登陆了

第一次没有token 重定向到sso 登陆操作 生成token了 就重定向回系统 回来后有token了 就顺利登陆

第二个系统

其他系统重定向到sso 已经有了token 不用生成了 那就直接拿着token重定向回本系统 我们都去sso.com下取token
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值