CAS 单点登录之自定义登录

本文介绍了如何在已有项目中集成CAS单点登录,并保持自定义登录页面。针对老项目,作者建议创建独立登录服务,通过拦截请求验证后跳转,以保持可扩展性。此外,还分享了一种改造CAS,使用自定义过滤器和登录处理类的方法,涉及到客户端和CAS服务器端的配置修改,包括web.xml、过滤器、登录页面、webflow流程、错误处理页面等的调整。
摘要由CSDN通过智能技术生成

开源的 CAS 单点登录本身已经提供了一个统一的登录页面,也就是我们配置好之后,所有的没有登录的请求都会拦截到自带的登录页面,我们可以根据自己的需求来改造这个页面,但是,需求是多种多样的并且有时候总是更改的,我就碰到过这种情况,有时就会让人很崩溃。

很多时候,我们都是接手别人的代码,而且大多都是比较成熟,并且有一定时间的项目,我们总是在前人的基础进行修修补补。就拿单点登录来说,我相信大多数项目都有一套自己比较成熟的登录过滤机制,如果我们集成单点登录功能,也是使用我们以前的登录页面,这时候我们就要对 CAS 进行改造。

在我第一次接手这个需求之前,我在网上查找了很多资料,大多数都是教我们将 CAS 集成进项目,我在集成的过程发现,因为我的项目本来就是一个老项目,使用的是 Spring Security 来进行登录过滤,要将原来的登录逻辑改成 CAS 的,这个比较难,往往会碰到很多 Bug,代码的耦合度有点高,牵一发而动全身,不胜其烦。所以,我感觉这个方法并不适合一个老项目。后来,我想了一个办法,另外单独写了一个登录的服务,所有的请求都拦截到这个新的服务,然后根据访问的链接,验证成功后再跳转回去,这样做的好处有,可扩展性比较强,以后如果有新的项目要加进来,只需添加一些配置即可,缺点就是需要单独启动一个服务,这样开销较大,要是这个服务崩,其他的也登录不进去了。

这时,我们就要发挥搜索引擎的巨大优势和身为程序员的主观能动性了,在我一通搜索之后,我终于找到了一个比较合适的解决方案了,那就是改造 CAS,自定义登录页面。

参考文章:http://lsz1023-126-com.iteye.com/blog/2098973

方法

将 CAS 原有的过滤器改为我们自己的过滤器,新增一个 remoteLogin 类,将 CAS 原有的处理登录的类换成我们自己的,其他的校验还是 CAS 自己的,新增一个校验登录失败的页面,将错误信息返回给客户端。我们需要修改客户端和 CAS 认证服务器端两处。

修改客户端
1. 新增 RemoteAuthenticationFilter.java,可以自定义路径,web.xml 文件能够正确引用即可。

public class RemoteAuthenticationFilter extends AbstractCasFilter {
   

  public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";

  /**.
   * 本地登陆页面URL.
   */
  private String localLoginUrl;

  /**.
   * The URL to the CAS Server login.
   */
  private String casServerLoginUrl;

  /**.
   * Whether to send the renew request or not.
   */
  private boolean renew = false;
  /**.
   * Whether to send the gateway request or not.
   */
  private boolean gateway = false;

  protected void initInternal(final FilterConfig filterConfig) throws ServletException {
    super.initInternal(filterConfig);
    setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
    log.trace("Loaded CasServerLoginUrl parameter: " + this.casServerLoginUrl);
    setLocalLoginUrl(getPropertyFromInitParams(filterConfig, "localLoginUrl", null));
    log.trace("Loaded LocalLoginUrl parameter: " + this.localLoginUrl);
    setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
    log.trace("Loaded renew parameter: " + this.renew);
    setGateway(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
    log.trace("Loaded gateway parameter: " + this.gateway);
  }

  public void init() {
    super.init();
    CommonUtils.assertNotNull(this.localLoginUrl, "localLoginUrl cannot be null.");
    CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
  }


  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
      FilterChain filterChain) throws IOException, ServletException {
    final HttpServletRequest request = (HttpServletRequest) servletRequest;
    final HttpServletResponse response = (HttpServletResponse) servletResponse;
    final HttpSession session = request.getSession(false);
    final String ticket = request.getParameter(getArtifactParameterName());
    final Assertion assertion = session != null
        ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
    final boolean wasGatewayed = session != null && session.getAttribute(CONST_CAS_GATEWAY) != null;
    // 如果访问路径为localLoginUrl且带有validated参数则跳过
    URL url = new URL(localLoginUrl);
    final boolean isValidatedLocalLoginUrl = request.getRequestURI().endsWith(url.getPath())
        && CommonUtils.isNotBlank(request.getParameter("validated"));

    if (!isValidatedLocalLoginUrl && CommonUtils.isBlank(ticket) && assertion == null
        && !wasGatewayed) {
      log.debug("no ticket and no assertion found");
      if (this.gateway) {
        log.debug("setting gateway attribute in session");
        request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
      }
      final String serviceUrl = constructServiceUrl(request, response);
      if (log.isDebugEnabled()) {
        log.debug("Constructed service url: " + serviceUrl);
      }
      String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
          getServiceParameterName(), serviceUrl, this.renew, this.gateway);
      // 加入localLoginUrl
      urlToRedirectTo += (urlToRedirectTo.contains("?") ? "&" : "?") + "loginUrl="
          + URLEncoder.encode(localLoginUrl, "utf-8");
      if (log.isDebugEnabled()) {
        log.debug("redirecting to '" + urlToRedirectTo + "'");
      }
      response.sendRedirect(urlToRedirectTo);
      return;
    }
    if (session != null) {
      log.debug("removing gateway attribute from session");
      session.setAttribute(CONST_CAS_GATEWAY, null);
    }
    filterChain.doFilter(request, response);
  }

  public final void setRenew(final boolean renew) {
    this.renew = renew;
  }

  public final void setGateway(final boolean gateway) {
    this.gateway = gateway;
  }

  public final void setCasServerLoginUrl(final String casServerLoginUrl) {
    this.casServerLoginUrl = casServerLoginUrl;
  }

  public final void setLocalLoginUrl(String localLoginUrl) {
    this.localLoginUrl = localLoginUrl;
  }
}

2. web.xml ,将原来的过滤器换成上面的过滤器,然后配置以下配置。如果要实现单点登出功能,只需将单点登出的配置放到最上面,使用 CAS 自带的单点登出功能即可。

<!-- 单点登出 -->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

     <filter>
          <filter-name>CAS Single Sign Out Filter</filter-name>
          <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
          <init-param>
               <param-name>casServerUrlPrefix</param-name>
               <!-- 只需改成 CAS 认证服务器的地址,例如 -->
               <param-value>http://127.0.0.1:8080/cas</param-value>
          </init-param>
    </filter>
    <filter-mapping>
            <filter-na
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值