美文网首页
CAS-Server之Ticket体系

CAS-Server之Ticket体系

作者: a乐乐_1234 | 来源:发表于2018-04-06 18:09 被阅读0次
    • ticket是Server端与client端通信的票据,有了ticket服务才知道你是首次请求认证还是认证通过来验证的。
    • cas服务器默认实现了2种认证方式,一种是普通登录,也就是按照基本的cas流程认证,还有一种是代理认证,这种认证方式因为涉及到一个业务系统请求另一个业务系统资源所以复杂一些。
    • 基本认证流程cas提供了TicketGrantingTicket(TGT)和ServiceTicket(ST)两种Ticket,代理认证在基本认证基础上增加了ProxyGrantingTicket(PGT,PGTIOU)和ProxyTicket(PT)两种。

    Ticket实体

    Ticket接口

    该接口定义了Ticket基本的属性,如id,isExpired(是否过期),CreationTime(创建时间),CountOfUses(当前ticket以被使用次数,每验证一次会加1),TicketGrantingTicket(每个Ticket实现都是基于TicketGrantingTicket)

    Ticket分类

    TicketGrantingTicket(TGT)

    从Ticket接口可知TicketGrantingTicket是所有Ticket实现的基础(不包括自己),没有TicketGrantingTicket是不可能生成其他的Ticket。
    那TicketGrantingTicket何时生成呢?先看下源码

    public interface CentralAuthenticationService {
      //生成TicketGrantingTicket
      TicketGrantingTicket createTicketGrantingTicket(AuthenticationContext context)
    }
    

    可知,必须先有Authentication实例,才会生成TicketGrantingTicket,Authentication实例是用户信息认证成功后cas服务器创建的。

    ServiceTicket(ST)

    ServiceTicket是客户端进行验证的票据,服务端验证通过才会将用户信息返回给客户端。
    ServiceTicket生成必须要ticketGrantingTicketId

    public interface CentralAuthenticationService {
        //生成ServiceTicket
        ServiceTicket grantServiceTicket(String ticketGrantingTicketId, Service service, AuthenticationContext context)
        //验证ServiceTicket
        Assertion validateServiceTicket(String serviceTicketId, Service service) 
    }
    
    ProxyGrantingTicket(PGT,PGTIOU)

    ProxyGrantingTicket继承TicketGrantingTicket,说明ProxyGrantingTicket只是一种特殊的TicketGrantingTicket,特殊点就是在代理认证模式下使用。
    ProxyGrantingTicket是在代理端验证serviceTicket的时候生成的,代理端验证serviceTicket时除了传serviceTicketId还会传pgtUrl参数,表示接收PGT和PGTIOU的url,这点可看org.jasig.cas.web.AbstractServiceValidateController#handleRequestInternal方法。
    代理端验证serviceTicket后,cas服务端除了返回assertion信息,还会返回pgtIou,代理端拿着这个pgtIou去存储PGT和PGTIOU映射的地方找到PGT,然后拿着PGT和targetService再次请求cas服务器(/proxy),返回ProxyTicket。具体可看代理流程序列图。

    public interface CentralAuthenticationService {
      //生成ProxyGrantingTicket
      ProxyGrantingTicket createProxyGrantingTicket(String serviceTicketId, AuthenticationContext context)
    }
    
    org.jasig.cas.web.AbstractServiceValidateController#handleRequestInternal方法
    //proxyHandler使用Cas20ProxyHandler
    String proxyIou = null;
    if (serviceCredential != null && this.proxyHandler.canHandle(serviceCredential)) {
        proxyIou = this.proxyHandler.handle(serviceCredential, proxyGrantingTicketId);
        ...省略其他代码
     }
    
    ProxyTicket(PT)

    ProxyTicket继承ServiceTicket,说明也是一种特殊的ServiceTicket,是给被代理端验证用的,代理端通过ProxyGrantingTicket获取到ProxyTicket后,请求被代理端带上该ProxyTicket,被代理端那着该ProxyTicket去cas服务器验证(/proxyValidate),验证过程同基本验证流程一样,返回assertion。

    附上类图


    TGT
    ST
    PGT
    PT

    Ticket存储

    TicketRegistry接口

    该接口定义了Ticket的增删改查,搜索整个工程在DefaultTicketRegistrySupport、TicketRegistryCleaner和CentralAuthenticationServiceImpl三个类中使用了该接口。

    • DefaultTicketRegistrySupport用于通过ticketGrantingTicketId去TicketRegistry中获取TicketGrantingTicket中的属性如Authentication、Principal、Attributes等。
    • TicketRegistryCleaner是一个Job,用于定时清理TicketRegistry中过期的Ticket。
    • CentralAuthenticationServiceImpl用于生成*Ticket比添加到TicketRegistry中。
    DefaultTicketRegistry

    TicketRegistry的默认实现,使用一个HashMap存储Ticket,这种在系统小的时候可以,系统数据多的时候就要考虑用第三方存储了,如数据库或缓存。

    AbstractDistributedTicketRegistry

    一个分布式Ticket存储实现(抽象类),具体采用哪种方式需要自己继承该类。该类中有getProxiedTicketInstance方法,用于生成一个ticket代理。


    getProxiedTicketInstance

    为什么要生成代理呢?
    点开任意一个代理实现,发现代理类中部分方法添加了事务处理且在同种方法中多了一个updateTicket()方法,如下图,以TicketGrantingTicketDelegator为例


    TicketGrantingTicketDelegator
    1. 这也很好理解,因为是对第三方储存的操作且分成了多个步骤所以叫加事务处理。至于增加updateTicket方法是因为,每次对Ticket的修改都会改变Ticket的状态,如previousLastTimeUsed、lastTimeUsed、countOfUses(见updateState方法)
    2. 那么重点来了,该怎么用。之前从DefaultTicketRegistry中取得都是原始Ticket,现在要改成代理Ticket,只需在自己的实现类中返回Ticket的方法中调用getProxiedTicketInstance方法将原始Ticket换成代理Ticket返回就行了,记住只在返回Ticket的方法中转换,更新和修改方法不变。只有两个方法getTicket(String ticketId)和getTickets()方法。
    3. 各个Ticket实体中已经加了JPA注解,当使用数据库存储时,可以将整个Ticket实体存到数据库,只需表字段和实体字段一一对应,CAS想的真是周到。

    Ticket生成

    TicketFactory接口
      //获取Ticket
      <T extends TicketFactory> T get(Class<? extends Ticket> clazz);
    
    TicketGrantingTicketFactory接口
      //生成TicketGrantingTicket,默认实现DefaultTicketGrantingTicketFactory
      <T extends TicketGrantingTicket> T create(Authentication authentication);
    
    ServiceTicketFactory接口
      //生成ServiceTicket,默认实现DefaultServiceTicketFactory
      <T extends Ticket> T create(TicketGrantingTicket ticketGrantingTicket,Service service,boolean credentialsProvided);
    
    ProxyGrantingTicketFactory接口
      //生成ProxyGrantingTicket,默认实现DefaultProxyGrantingTicketFactory
      <T extends ProxyGrantingTicket> T create(ServiceTicket ticket, Authentication authentication);
    
    ProxyTicketFactory接口
    //生成ProxyTicket,默认实现DefaultProxyTicketFactory
    <T extends Ticket> T create(ProxyGrantingTicket ticketGrantingTicket,Service service);
    

    每个实现类中都有默认的TicketId生成器和ExpirationPolicy(过期策略),如果需要实现自己的在xml中替换就行了

    相关文章

      网友评论

          本文标题:CAS-Server之Ticket体系

          本文链接:https://www.haomeiwen.com/subject/ppdshftx.html