因为有需要要实现内外网双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)踩坑经验 重定向次数多