因为有需要要实现内外网双IP拜访同一个利用,然而以后已部署的利用应用的cas+shiro的跳转url在spring的配置xml中写死的,所以须要实现判断起源HOST动静单点登录和跳转

继承FormAuthenticationFilter动静扭转各个url

package com.bajins.common;import java.io.IOException;import javax.servlet.ServletContext;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.cas.CasFilter;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.apache.shiro.web.filter.authc.LogoutFilter;import org.apache.shiro.web.util.WebUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.ApplicationContext;import org.springframework.util.StringUtils;import org.springframework.web.context.support.WebApplicationContextUtils;import com.bajins.common.shiro.cas.CasUserRealm;/** * @Title: ImsAuthenticationFilter.java * @Package com.bajins.common * @Description: shiro动静扭转loginUrl * @author: https://www.bajins.com * @date: 2021年4月15日 下午3:07:18 * @version V1.0 * @Copyright: 2021 bajins.com Inc. All rights reserved. */public class ImsAuthenticationFilter extends FormAuthenticationFilter {    private static transient final Logger log = LoggerFactory.getLogger(ImsAuthenticationFilter.class);    private static final String FLAG = "/login?service=";    private String clientUrl;    private String serverUrl;    /**     * @return the clientUrl     */    public String getClientUrl() {        return clientUrl;    }    /**     * @param clientUrl the clientUrl to set     */    public void setClientUrl(String clientUrl) {        this.clientUrl = clientUrl;    }    /**     * @return the serverUrl     */    public String getServerUrl() {        return serverUrl;    }    /**     * @param serverUrl the serverUrl to set     */    public void setServerUrl(String serverUrl) {        this.serverUrl = serverUrl;    }    @Override    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {        HttpServletRequest httpServletRequest = (HttpServletRequest) request;        String contextPath = httpServletRequest.getContextPath();        // url - uri = domain        int len = httpServletRequest.getRequestURL().length() - httpServletRequest.getRequestURI().length();        String domain = httpServletRequest.getRequestURL().substring(0, len);        /*String reg = "^(192\\.168|172\\.(1[6-9]|2\\d|3[0,1]))(\\.(2[0-4]\\d|25[0-5]|[0,1]?\\d?\\d)){2}$"                + "|^10(\\.([2][0-4]\\d|25[0-5]|[0,1]?\\d?\\d)){3}$";        //String reg = "(10|172|192|127)\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}"        //        + "|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})";        Pattern p = Pattern.compile(reg);        Matcher matcher = p.matcher(ipAddress);        boolean isIntranet = matcher.find();        if (isIntranet || httpServletRequest.getRemoteHost().equals("172.16.0.91")) { // 如果是内网            WebUtils.issueRedirect(request, response, domain + "/cas" + loginUrl);        } else {                    }*/        // 获取servletContext容器        ServletContext sc = httpServletRequest.getSession().getServletContext();        // 获取web环境下spring容器        ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sc);        CasUserRealm casUserRealm = (CasUserRealm) ac.getBean("casUserRealm");        CasFilter casFilter = (CasFilter) ac.getBean("casFilter");        LogoutFilter logoutFilter = (LogoutFilter) ac.getBean("logoutFilter");        ShiroFilterFactoryBean shiroFilter = (ShiroFilterFactoryBean) ac.getBean("&shiroFilter");        // 依据客户端url中的host动静替换url        String client = domain + contextPath;        String clientLoginUrl = client + "/login";        casUserRealm.setCasServerUrlPrefix(domain + getServerUrl());        casUserRealm.setCasService(clientLoginUrl);        casFilter.setFailureUrl(client + "/index");        casFilter.setSuccessUrl(client + "/");        // casFilter.setLoginUrl(loginUrl);        logoutFilter.setRedirectUrl(domain + getServerUrl() + FLAG.replace("login", "logout") + clientLoginUrl);        shiroFilter.setLoginUrl(domain + getServerUrl() + FLAG + clientLoginUrl);        log.info("login跳转地址:{}", this.getLoginUrl());        WebUtils.issueRedirect(httpServletRequest, response, this.getLoginUrl()); // 302跳转    }    /*@Override    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {        return false;    }*/    /*@Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        String loginUrl = this.getLoginUrl();        Subject subject = getSubject(request, response);        if (subject.getPrincipal() == null) {// 示意没有登录,重定向到登录页面            saveRequest(request);            WebUtils.issueRedirect(request, response, loginUrl);        } else {            if (StringUtils.hasText(loginUrl)) {                WebUtils.issueRedirect(request, response, loginUrl);            } else {                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);            }        }        return true;    }*/    /**     * 获取用户实在IP地址     * <p>     * 当咱们通过request获取客户端IP时,如果对本身服务器做了反向代理。 通过request.getRemoteAddr();可能获取到的是代理服务器的IP,而无奈获取到用户申请IP     *     * @param request     * @return java.lang.String     */    public static String getIpAddress(HttpServletRequest request) {        // X-Real-IP:Nginx服务代理        String ipAddresses = request.getHeader("X-Real-IP");        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            // Proxy-Client-IP:Apache 服务代理            ipAddresses = request.getHeader("Proxy-Client-IP");        }        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            // WL-Proxy-Client-IP:WebLogic 服务代理            ipAddresses = request.getHeader("WL-Proxy-Client-IP");        }        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            // HTTP_CLIENT_IP:有些代理服务器            ipAddresses = request.getHeader("HTTP_CLIENT_IP");        }        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            ipAddresses = request.getHeader("HTTP_X_FORWARDED_FOR");        }        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            // X-Forwarded-For:Squid 服务代理 和 Nginx服务代理            ipAddresses = request.getHeader("X-Forwarded-For");        }        // 有些网络通过多层代理,那么会获取到以逗号(,)宰割的多个IP,第一个才是实在IP        int index = ipAddresses.indexOf(",");        if (index != -1) {            ipAddresses = ipAddresses.substring(0, index);        }        if (!StringUtils.hasText(ipAddresses) || "unknown".equalsIgnoreCase(ipAddresses)) {            ipAddresses = request.getRemoteAddr();        }        return ipAddresses;    }}

批改Spring配置xml

<bean id="imsAuthenticationFilter" class="com.bajins.common.ImsAuthenticationFilter">    <property name="serverUrl" value="${cas.server}" />    <property name="clientUrl" value="${cas.client}" /></bean><!-- Shiro的Web过滤器 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">    <property name="securityManager" ref="securityManager" />    <!-- 原来写死的配置 -->    <!-- <property name="loginUrl" value="${cas.server}/login?service=${cas.client}/login" /> -->    <property name="loginUrl" value="/login?service=${cas.client}/login" />    <property name="unauthorizedUrl" value="/unauthorized" />    <property name="filters">        <util:map>            <!-- 这里把自定义的过滤器退出 -->            <entry key="authc" value-ref="imsAuthenticationFilter" />            <entry key="authl" value-ref="loginControlFilter" />            <entry key="cas" value-ref="casFilter" />            <entry key="logout" value-ref="logoutFilter" />            <entry key="casLogout" value-ref="casLogoutFilter" />        </util:map>    </property>    <!-- 指定拜访地址通过指定Filter过滤 -->    <property name="filterChainDefinitions">        <value>            /common/** = anon            /css/** = anon            /js/** = anon            /fileUpload/**=anon            /api/** = anon            /changeLocale=anon            <!-- 留神:这里不能用自定义的过滤器,否则死循环重定向 -->            /login = authl,casLogout,cas            /logout = logout            <!-- 应用自定义的过滤器 -->            /** = authc,casLogout,user        </value>    </property></bean>

参考:

  • 解决CAS内外网双IP拜访的问题
  • 双网隔离环境下CAS单点登录的解决方案
  • CAS内外网都能拜访配置阐明
  • DataViz CAS 单点登录集成 · dataviz
  • springboot shiro 多realm多loginUrl设置(动静扭转loginUrl)踩坑经验 重定向次数多