• 自定义Token的CAS登录


    工作中实际遇到的需求,我们有一个旧系统,用了CAS的单点登录,现在有一个外部系统,准备从它那里单点进来,这个外部系统提供了一个token参数来标记这是哪一个用户,我们用他们提供的方式解析出对应的用户,以这个用户从CAS登录进系统。

    有关CAS登录的分析网上多如牛毛,这里不准备多作分析了,直接上解决过程。

    这里实现是基于我们以前系统的,是CAS 3.5.2
    • 首先在登录流程文件login-webflow.xml里在on-start节点后面插入
    <decision-state id="tokenCheck">
       <if test="requestParameters.token != null and requestParameters.token != ''" then="tokenValidate" else="ticketGrantingTicketExistsCheck" />
    </decision-state>

    在这里检查是否有token参数,有的话执行token验证,没有的话走正常流程,ticketGrantingTicketExistsCheck就是原有的正常流程。

    • 定义token验证节点
    <action-state id="tokenValidate">
       <evaluate expression="tokenLoginAction.doExecute(flowRequestContext)" />
       <transition on="error" to="generateLoginTicket" />
       <transition on="success" to="sendTicketGrantingTicket" />
    </action-state>

    失败则走generateLoginTicket分支,会生成一个LT,并重定向到登录页面,这也是通常页面登录失败后的路径

    成功则走sendTicketGrantingTicket分支,即页面正常登录成功时走的路径

     
    • 实现token验证流程节点

    在cas-servlet.xml里添加添加tokenLoginAction Bean

    <bean id="tokenLoginAction" class="org.jasig.cas.web.flow.TokenLoginAction"
        p:centralAuthenticationService-ref="centralAuthenticationService" />

    实现TokenLoginAction

    这里主要解析token,并生成TGT。主要代码如下:

    HttpServletRequest request = WebUtils.getHttpServletRequest(context);
    String token = request.getParameter("token");
    
     try {
    
      //解析Token,略。。。。。。
    
       CasCredentials credentials = new CasCredentials();
       credentials.setUsername(userName);
       credentials.setPassword("");
       credentials.setNoAuth(true);
      
       String tgt = centralAuthenticationService.createTicketGrantingTicket(credentials);
       WebUtils.putTicketGrantingTicketInRequestScope(context,tgt);
      
     } catch (Exception e) {
       e.printStackTrace();
      return "error";
     }
     
     return "success";
    TokenLoginAction的主要逻辑代码

    上面centralAuthenticationService是注入的属性,

    CasCredentials则是继承自UsernamePasswordCredentials的一个自定义Credentials,在用户名、密码基础上添加了一个noAuth属性,用来标记是不是需要验证密码。这里由外系统提供的token保证安全性,把noAuth设为true。

    而登录验证逻辑在createTicketGrantingTicket这个方法里,验证未通过会抛出异常。

    真正验证的地方则是在authenticationManager里,里面有authenticationHandlers定义了验证方法
    • 修改登录验证逻辑

    login-webflow.xml顶部把credentials的定义先改了

    <var name="credentials" class="com.cas.util.CasCredentials" />

    deployerConfigContext.xml找到自定义登录验证所在

    <bean id="authenticationManager" class="">
       <property name="authenticationHandlers">
      <list>
                               <bean
        class="com.cas.util.QueryUserAuthenticationHandler">
    ......
                               </bean>
                           </list>
       </property>
    </bean>

    在这个QueryUserAuthenticationHandler class里,验证密码之前加入

      if (CasCredentials.class.isInstance(credentials)) {
       if (((CasCredentials)credentials).isNoAuth())
        return true;
      }

    这样就完成了传入第三方token的CAS登录。

    似乎是完成了,但其实还有一些东西,

    比如第三方进来的时候是不用他们传Service这个参数的,而这个参数是在CAS登录初始化时处理掉的,后面没有地方自己往request里加这个参数让CAS来处理它,自己写requestscope里写Service对象又很麻烦,看了下代码,得注入很多东西才行。这样就在进入CAS流程前,自己往请求里塞一个Service参数,然后重定向到CAS登录的url。

    再比如,这次是别人提供Token用他们的方法解;以后有需求是我们提供一个Token出去,接收进来后用我们的方法自己解。所以其实TokenLoginAction那里解析Token其实是解本方提供出去的Token。解别人的Token呢前置到塞Service参数那个地方,那里解析出来用户名后,再用自己的方法生成一个Token发给CAS。这样就把第三方的Token解析分离出去了,CAS登录的地方不会跟别人的实现绑在一起。

  • 相关阅读:
    mysql 常用语句
    easyui 时间格式化
    sql学习
    Java基础知识
    windows部署环境(laravel项目)
    gradle spring boot构建项目
    linux mysql操作
    composer
    linux常用命令
    mongodb使用手册
  • 原文地址:https://www.cnblogs.com/lichdr/p/10316972.html
Copyright © 2020-2023  润新知