CAS5.2x单点登录(七)-------------单点退出

单点登出产生的原因

前几篇我们已经讲了如何搭建单点登录以及他的服务注册等,我们也清楚单点登录的目的是为了不用频繁的去登录,基本上有单点登录的地方就有单点登出,因为这两个感觉是绑定在一起的。我们知道cas单点登录成功后,cas会为我们每个客户端生成一个session,然后再次访问这个客户端的接口的时候,我们客户端引入的cas的jar包会去判断,这个接口是否有session,如果没有的话就继续判断下面的,如果有的话就直接跳过。但是我们想象一下,当我们点击caslogout的时候,发现其他子系统还能登陆,但是却不能再次免登录到其他的系统。这可能就有点怪怪的,单点登录不是一个登录,接入进来的子系统就免登录了吗?事实是这样的,但是cas的原理其实是靠tgt来记录登录的信息,也就是当我们登录的时候,我们浏览器会记录一个tgt,下次子系统登录的时候,会带着浏览器的tgt如果存在的话,那么就授予票据,之后的一系列操作就不说了。这样就达到免登录的效果了。但是有这样的一个场景:我们接入cas的子系统有3个,这时候我们通过cas单点登录开启了两个子系统,这时候我执行一下caslogout,我们发现已经登录上去的两个子系统没有受影响,但是当我们点击最后一个子系统的时候发现他需要登录。刚开始我还以为我自己弄错了,但是试了好久还是这个问题。我们上面说了tgt的事情(可以自己去了解一下cas单点登录的原理),我们执行caslougout的时候其实就是将cas的登录tgt给只为无效,所以当我们第三个子系统去登录的时候,cas发现他没有session,同时也没有st,这个时候就会转到cas登录页面,但是如果cas已经登录的话那么就能直接获取到st,可是因为我们之前的退出已经将cas的tgt给只为无效了,所以cas发现没有登录,就要去重新登录。但是这样客户一定不会满意,因为他们要的效果是,一个退出其他的都要退出,一个登录其他的都要登录,这时候就需要单点退出了,也就是我接下来要讲的内容。

单点登出的原理

单点登出的原理其实不难,cas他其实已经帮我们实现了这个退出的功能,我画了个流程图便于大家理解

这里写图片描述
他的退出流程其实就是上面的这个流程图,至于他是如何退出的,你可以参考一下singleout的源码,其实也不是很难,如果了解cas的原理的话,可能知道st,其实在cas写session的时候其实已经将st也同时给保存下来了,删除的时候也会通过st去删除。这个源码里面有,如果需要的话,我有时间可以解读一下源码。

退出的url在哪里设置?

上面说了cas退出的流程,我们发现其中有个logouturl,这个是在哪设置的呢?
其实cas的退出在官方文档中已经写过了,
cas的退出有三种模式:

  • NONE:不支持单点登录
  • BACK_CHANNEL:隐式退出(默认)
  • FRONT_CHANNEL:显式退出
    第一种我们就不说了:
    隐式退出:cas发送通知,业务系统后端主动注销用户
    显式退出:cas发送数据给客户端,客户端接收并且注销用户,再转发到cas往下处理注销流程
    而我们cas默认采用的是第二种,我也就用第二种来讲解。
    我们设置退出的url有好多种方式,但是原理都是一样的。我们先使用json格式文件来说,
"@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://localhost:8080.*",
  "name": "name",
  "id": 10000010,
  "description": "desc",
  "evaluationOrder": 1,
  "logoutUrl": "http://localhost:8080"

我们看到上面的一个logouturl的设置,其实他设置的也没有多难,只需要这样设置就ok了,上面的描述文件的各个字段就不用我多说了吧,如果我们要选择模式的话就要自己在这上面加入一个模式,你也可以参考cas的文档进行填写,cas的文档已经很详细的说明了哪些是必填的哪些是选填的。
上面使用的json文件的方式,对于我来说总感觉有点麻烦,我这边使用的jpa数据库存储的方式,其实原理以及字段都是一致的:我们使用restful风格的接口去注册这样的服务

@RequestMapping(value = "/addClient/{protocol}/{serviceId}/{id}",method = RequestMethod.GET) 
      public String addClient(@PathVariable("serviceId") String serviceId,@PathVariable("protocol") String protocol
              ,@PathVariable("id") int id) throws IOException {
          String url=protocol+"://"+serviceId;
          RegisteredService svc = servicesManager.findServiceBy(url);
          if(svc!=null){
              return "0";//0代表着已存在这个服务,服务是通过正则去匹配的,所以这边建议使用ip或者域名+端口号
          }
          String a="^"+url+".*";//匹配以这个url开始的url
          RegexRegisteredService service=new RegexRegisteredService();
          ReturnAllAttributeReleasePolicy re=new ReturnAllAttributeReleasePolicy();
          service.setServiceId(a);
          service.setId(id);
          service.setAttributeReleasePolicy(re);
          //将name统一设置为servicesId
          service.setName(serviceId);
          service.setLogoutType(LogoutType.BACK_CHANNEL);
          service.setLogoutUrl(new URL(url));//这个是为了单点登出而作用的
          servicesManager.save(service);
          servicesManager.load();
          return "1";//添加服务成功
    }

到这里我们cas的退出也已经讲完了,也可以实现单点退出的功能,但是对于分布式的话,就会出现问题,因为分布式的系统的话是为了负载均衡,所以退出的时候可能执行的是另一个系统,可能导致session不成功,这边的话我还要去看看怎么解决这个问题

你可能感兴趣的:(cas)