上上篇博文中介绍了如何搭建cxf和spring环境,本文将围绕如何在此环境下编写拦截器,只允许已经配置好的IP地址访问服务器端。
一、修改配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- WebService服务 -->
<bean id="inter" class="com.yolanda.cxfTest.AImpl"/>
<jaxws:endpoint id="cxfService" implementor="#inter" address="/CxfService" >
<jaxws:inInterceptors>
<ref bean="ipInIntercept"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
<!--毫秒单位 name 为 webservice 的域名 或者地址-->
<http-conf:conduit name="${train.api.domain.name}.*">
<http-conf:client ConnectionTimeout="10000" ReceiveTimeout="20000"/>
</http-conf:conduit>
<bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<!-- 自定义拦截器-->
<bean id="ipInIntercept" class="com.intercept.IpInIntercept"/>
<!-- CXF 全局的拦截器-->
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logIn"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOut" />
</cxf:outInterceptors>
</cxf:bus>
</beans>
在这个地方遇到一个标签错误,错误提示
cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'jaxws:inInterceptors'.参见我的另一篇博文http://blog.csdn.net/yolanda_nuonuo/article/details/47016981
二、web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>cxfTest</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- WebServices设置 -->
<servlet>
<servlet-name>CxfService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CxfService</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
三、拦截器的编写
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Ip拦截器
*
*/
public class IpInIntercept extends AbstractPhaseInterceptor<Message>{
private List<String> ipList = new ArrayList<String>();
private final static Logger logger = LoggerFactory.getLogger(IpInIntercept.class);
public IpInIntercept() {
super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
String ipAddress = "";
ConnOracle co = new ConnOracle();
co.getConn();
String sql = "select * from IPADDR";
co.sqlExe(sql);
boolean flag = false;
int count = 0;
if (null != request && count <= 10) {
ipAddress = getUsrIPAddr(request);//获取客户端的IP地址
logger.info("获取到客户端的IP地址是:" + ipAddress);
System.out.println("获取到客户端的IP地址是:" + ipAddress);
count++;
for (String ipString : ipList) {
if (ipString.equals(ipAddress)) {
flag = true;
break;
}
}
}
if (!flag) {
throw new Fault(new IllegalAccessException("IP address " + ipAddress + " is not allowed"));
}
}
/**
* 获取客户端ip地址
* @param request
* @return
*/
public String getUsrIPAddr(HttpServletRequest request) {
String ip = "";
//1.首先考虑有反向代理的情况,如果有代理,通过“x-forwarded-for”获取真实ip地址
ip = request.getHeader("x-forwarded-for");
//2.如果squid.conf的配制文件forwarded_for项默认是off,则:X-Forwarded-For:unknown。考虑用Proxy-Client-IP或WL-Proxy-Client-IP获取
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
//3.最后考虑没有代理的情况,直接用request.getRemoteAddr()获取ip
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
//4.如果通过多级反向代理,则可能产生多个ip,其中第一个非unknown的IP为客户端真实IP(IP按照','分割)
if(ip != null && ip.split(",").length > 1){
ip = (ip.split(","))[0];
}
//5.如果是服务器本地访问,需要根据网卡获取本机真实ip
if("127.0.0.1".equals(ip)) {
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
logger.error(e.getMessage(),e);//获取服务器(本地)ip信息失败
return "";
}
}
// 6.校验ip的合法性,不合法返回""
if(!isValidIp(ip)) {
return "The ip is invalid.";
}else {
return ip;
}
// return ip;
}
/**
* 判断是否为合法IP地址
* @param ipAddress
* @return
*/
private boolean isValidIp(String ipAddress) {
boolean retVal = false;
try {
if(ipAddress!=null && !"".equals(ipAddress)){
Pattern pattern = Pattern.compile("([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}");
retVal = pattern.matcher(ipAddress).matches();
}
} catch(Exception e){
logger.error(e.getMessage(), e);
}
return retVal;
}
}
三、数据库工具类
由于使用了oracle数据库,所以还要编写数据库工具类如下。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 数据库连接
*
*/
public class ConnOracle {
//数据库连接驱动
public static final String driver = "oracle.jdbc.driver.OracleDriver";
//数据库连接地址
public static final String url = "jdbc:oracle:thin:@172.25.2.148:1521:ORCL";
//登录名
public static final String usr = "twj";
//密码
public static final String pwd = "123";
//数据库连接对象
private Connection conn = null;
//数据库预编译对象
private PreparedStatement ps = null;
//结果集
private ResultSet rs = null;
//结果字符串
private List<String> list = new ArrayList<String>();
/**
* 获取数据库连接
* @return conn
*/
public Connection getConn() {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection(url, usr, pwd);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭所有资源
*/
public void closeAll()
{
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}//if
}
/**
* 执行sql语句
* @param sqlString
*/
public List<String> sqlExe(String sqlString)
{
try {
ps = conn.prepareStatement(sqlString);
rs = ps.executeQuery();
while (rs.next()) {
list.add(rs.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}