使用Jetty对接CAS多网段认证服务

公司产品需要对接一个CAS认证服务的单点登录,拿到手上的时候有点懵逼,但是问题还是需要解决的,到网上查了一下,全是基于tomcat服务的,使用过滤器来实现的,但是我们系统用的是内嵌的Jetty服务器,怎么办呢?

在此之前你得了解一下Jetty服务器的结构,怎样集成过滤器,可以参考以下:

https://www.cnblogs.com/kxdblog/p/6368836.html?utm_source=itdadao&utm_medium=referral

我这里用的是cas-client-core.jar的第三方包,大家如果想更加了解可以去看一下里面的源码。

添加了过滤器之后,然后就是servlet了,自己业务的登录逻辑。

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal();
        if (principal == null) {
            logger.err("principal is null.");
            return;
        }
        String userName = principal.getName();
        if (userName == null) {
            try {
                throw new LogicalException("USER_NAME_IS_NULL", "USER_NAME_IS_NULL");
            } catch (LogicalException e) {
                e.printStackTrace();
            }
        }
        if (userName == null) {
            logger.err("userName is null.");
            return;
        }
        try {
            UserInfo userInfo = null;
            try {
                userInfo = this.beans.getUserCore().getModel().findUser(userName, null, null);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            if (null != userInfo) {
                // 根据用户信息获取网盘token
                // 创建token添加到cookie
                Env env = new Env(req, resp, "");
                LoginInfo loginInfo = this.beans.getAuthApi().createToken(env, userInfo, SyncConfig.TOKENAGE);

                Cookie panCookie = new Cookie("token", loginInfo.tokenInfo.token);
                panCookie.setPath("/");
                // 设置cookie时间
                panCookie.setMaxAge(-1);
                resp.addCookie(panCookie);

                req.getSession().setAttribute("runTimeUser", userInfo);

                // 重定向到xserver页面
                resp.sendRedirect(SyncConfig.PANURL);
            }
        } catch (Exception e) {
            logger.err("something error. userName:" + userName, e);
        }
    }


Jetty不像Tomcat一样初始化的时候web.xml就行,这个得自己添加到初始化里面去,才能起到作用。


        Class clazz = httpServer.getClass();
        Field field = clazz.getDeclaredField("handlers");
        field.setAccessible(true);
        List<Handler> handlers = (List<Handler>) field.get(httpServer);

        // 移除web init中注册的"/*"路径
        Iterator<Handler> iterator = handlers.iterator();
        while (iterator.hasNext()) {
            Handler handler = iterator.next();
            if (handler instanceof ServletContextHandler) {
                ServletContextHandler h = (ServletContextHandler) handler;
                if (h.getContextPath().equals("/")) {
                    iterator.remove();
                    break;
                }
            }
        }

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        ServletHandler handler = new ServletHandler();

        String filterHodlerPath = "/*";
        String filterPath = "/*";

        // 单点退出
        context.addEventListener(new SingleSignOutHttpSessionListener());

        //添加单点退出的过滤器
        FilterHolder singleSignOutFilterHolder = handler.addFilterWithMapping(SingleSignOutFilter.class, filterHodlerPath,
                EnumSet.of(DispatcherType.REQUEST));
        context.addFilter(singleSignOutFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));

        // 单点登录
        Map<String, String> params = new HashMap<>();
        SyncConfig.serverName = properties.getProperty("serverName");
        params.put("serverName", SyncConfig.serverName);

        SyncConfig.loginUrlsJson = JSONObject.parseObject(properties.getProperty("casServerLoginUrls"));
        SyncConfig.prefixJson = JSONObject.parseObject(properties.getProperty("casServerUrlPrefixs"));
        if (SyncConfig.loginUrlsJson.size() != SyncConfig.prefixJson.size()) {
            throw new LogicalException("CAS_CONFIG_ERROR", "CAS_CONFIG_ERROR");
        }
        params.put("casServerLoginUrls", properties.getProperty("casServerLoginUrls"));
        params.put("casServerUrlPrefixs", properties.getProperty("casServerUrlPrefixs"));

        for (String key : SyncConfig.prefixJson.keySet()) {
            params.put("casServerUrlPrefix", SyncConfig.prefixJson.getString(key));
            FilterHolder cas20ProxyReceivingTicketValidationFilterHolder = handler.addFilterWithMapping(
                    Cas20ProxyReceivingTicketValidationFilterWrapper.class, filterHodlerPath, EnumSet.of(DispatcherType.REQUEST));
            cas20ProxyReceivingTicketValidationFilterHolder.setInitParameters(params);
            context.addFilter(cas20ProxyReceivingTicketValidationFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
        }

        for (String key : SyncConfig.loginUrlsJson.keySet()) {
            params.put("casServerLoginUrl", SyncConfig.loginUrlsJson.getString(key));
            FilterHolder authenticationFilterHolder = handler.addFilterWithMapping(AuthenticationFilterWrapper.class, filterHodlerPath,
                    EnumSet.of(DispatcherType.REQUEST));
            authenticationFilterHolder.setInitParameters(params);
            context.addFilter(authenticationFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
        }

        FilterHolder httpServletRequestWrapperFilterHolder = handler.addFilterWithMapping(HttpServletRequestWrapperFilter.class,
                filterHodlerPath, EnumSet.of(DispatcherType.REQUEST));
        context.addFilter(httpServletRequestWrapperFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));

        FilterHolder assertionThreadLocalFilterHolder = handler.addFilterWithMapping(AssertionThreadLocalFilter.class, filterHodlerPath,
                EnumSet.of(DispatcherType.REQUEST));
        context.addFilter(assertionThreadLocalFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));



        context.setHandler(handler);
        ServletHolder sh = new ServletHolder(new SsoServlet(beans, logger));
        context.addServlet(sh, "/*");

        handlers.add(context);

注意:注销的Filter必须放在最前面。

多网段配置采用json配置文件来制作,在初始化的时候将Fiter重写(jar包内的是final,无法重写,需要自己修改一下jar包内容,重写的init需要将初始化存入json的各网断地址拿出来,doFilter需要用到,doFilter里面就需要对多网段和客户端地址进行判断对比匹配。)

public class Cas20ProxyReceivingTicketValidationFilterWrapper extends Cas20ProxyReceivingTicketValidationFilter {

    private JSONObject prefixJson;

    private String currentServerName;

    private String currentPrefixUrl;

    @Override
    protected void initInternal(FilterConfig filterConfig) throws ServletException {
        String casServerUrlPrefixs = filterConfig.getInitParameter("casServerUrlPrefixs");
        prefixJson = JSONObject.parseObject(casServerUrlPrefixs);
        currentPrefixUrl = filterConfig.getInitParameter("casServerUrlPrefix");
        for (String key : prefixJson.keySet()) {
            String value = prefixJson.getString(key);
            if (value.equalsIgnoreCase(currentPrefixUrl)) {
                currentServerName = key;
                break;
            }
        }
        super.initInternal(filterConfig);
    }
    

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        final String host = request.getHeader("Host");
        final String xHost = request.getHeader("X-Forwarded-For");

        final String comparisonHost;
        if (xHost != null && host == "localhost") {
            comparisonHost = xHost;
        } else {
            comparisonHost = host;
        }

        if (currentServerName.equalsIgnoreCase(comparisonHost)) {
            request.setAttribute("casServerUrlPrefix", currentPrefixUrl);
            super.doFilter(servletRequest, servletResponse, filterChain);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}

最后就是退出了。退出坑还是挺多的。给个链接参考一下,里面说的比较详细,我这里就不一一细说了。

https://www.cnblogs.com/codestory/p/5512104.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值