加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

4.6Webservice

发布时间:2020-12-16 21:50:05 所属栏目:安全 来源:网络整理
导读:个人印象笔记 在Web工程中发布Webservice WebService的安全设置即webservice的头部消息处理 Handler处理链的使用 1:在Web工程中发布Webservice: 1.1方法一: 先建一个Web工程,然后把要发布的Webservice的接口和实现类拷到Web工程的一个包下,并且 在接口类
个人印象笔记
在Web工程中发布Webservice
WebService的安全设置即webservice的头部消息处理
Handler处理链的使用
1:在Web工程中发布Webservice:
1.1方法一:
先建一个Web工程,然后把要发布的Webservice的接口和实现类拷到Web工程的一个包下,并且 在接口类前加上 @SOAPBinding(style = SOAPBinding.Style.RPC)
再写一个监听器,用来发布Webservice的,它会在工程启动的时候,自动发布我们的Webserice服务。
(建立监听器的步骤:建一个java类且实现ServletContextListener,然后实现contextInitialized()和contextDestroyed这两个函数,最后要在web.xml中配置 <listener><listener-class>com.listener.PublishServiceListener</listener-class></listener>)。
注意:这时候有个问题,就是当我们访问的时候,如果我们访问的是Webservice里的方法,就得访问 http://localhost:7070/first,
如果我们访问的方法是部署在Tomcat下的方法,就得访问 http://localhost:8080这个地址。
这样有个麻烦就是我们得记住两个端口号。
监听器的代码:

package com.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.xml.ws.Endpoint;

import com.webservice.First;

/**
?* 用于发布WebService
?*
?* @author ctd
?*
?*/
public class PublishServiceListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("工程初始化的操作");
/**
* 发布WebService
*/
Endpoint.publish("http://localhost:7070/first",new First());
System.out.println("通过WEB的方式发布Fist服务成功");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
?????System.out.println("工程销毁的操作");
}

}

客户端调用类:
package com.test;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

public class TestMain {
public static void main(String[] args) {
TestMain.callServlet();
TestMain.callService();
}

private static void callServlet() {
DefaultHttpClient httpClient = new DefaultHttpClient();
String url = "http://localhost:8080/WebService_Server_04/servlet/TestServlet";
HttpGet httpGet = new HttpGet(url);

try {
HttpResponse response = httpClient.execute(httpGet);

HttpEntity entity = response.getEntity();

System.out.println("enity = " + entity);
String responseStr = EntityUtils.toString(entity);

System.out.println(responseStr);
} catch (Exception e) {
e.printStackTrace();
}
}

private static void callService() {

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://localhost:7070/first?wsdl");

try {

StringBuffer soapXML = new StringBuffer();
soapXML
.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">");
soapXML.append("<SOAP-ENV:Header/>");
soapXML.append("<SOAP-ENV:Body>");
soapXML.append("<ns:add xmlns:ns="http://webservice.com/">");//这里的命名空间要和你自己的对应
soapXML.append("<x>11</x>");
soapXML.append("<y>55</y>");
soapXML.append("</ns:add>");

soapXML.append("</SOAP-ENV:Body>");
soapXML.append("</SOAP-ENV:Envelope>");

StringEntity soapEntity = new StringEntity(soapXML.toString());
httpPost.setEntity(soapEntity);
httpPost.setHeader("Content-Type","text/xml; charset=UTF-8");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String str = EntityUtils.toString(entity);

//System.out.println("str = " + str);

String addResult = str.substring(str.indexOf("<addResult>") + 11,
str.indexOf("</addResult>"));
System.out.println("addResult = " + addResult);

} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

}
}

1.2方法二:
服务端:
Webservice和Web工程是合在一起的。
步骤:
? ? ?这时要建立一个Web Service Project (optional Maven support)(不选加入Maven)工程,写一个Servlet类,运行看是否可以正常运行。然后建一个包名叫sss.webservice,在这个包里写一个实现类Login类,当要发布这个类的时候,右击这个包,选择New Web Service,然后根据自己的情况选择Strategy(假设选第二个),点击下一步。等到完成时,会生成一个代理类( 这个代理类才是WebService.Web service不一定要用接口,只是推荐使用接口而已.)和一个WSDL文件和Sun-jaxws.xml,然后Web.xml里会多了这些东西:
? //WSServlet这个类是帮助我们在Web工程中发布Web service的时候用到的
? //它最主要的任务是发布webservice
<servlet>
<servlet-name>PubSerivceServlet</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>PubSerivceServlet</servlet-name>
<url-pattern>/LoginPort</url-pattern>
</servlet-mapping>


注意:其中 com.sun.xml.ws.transport.http.servlet.WSServlet 这个类jdk里是没有的,所以得自己加jar包
就是 导入了myeclipse 的两个libraries就可以了,步骤: 工程上右键-》properties-》java build path -》 add libraries -》 选myeclipse libraries -》next 拉到最后选择最后两个库(jax-ws runtime 和 jax-ws api)。

最后像平常发布Web工程那样发布就好了,访问正常的Servlet还是和平常一样,访问Webservice时,后面得加 /LoginPort?这个( <url-pattern>/LoginPort</url-pattern>)。
前面说的这些,主要是解决两个端口变为一个端口的问题而已,这两种方式都可以用。
客户端调用:和平常的类似。
2、WebService的安全设置即webservice的头部消息处理
3种方案
? ? ?2.1名称/密码 直接定义在方法中。(String content,String userid,String password);(最常用)
? ? ?2.2名称/密码 不定义在方法中。 (Soap消息,分为head和body):
? ? ? ? ? ? ?? ?????2.2.1:放在显示的header消息中
? ? ? ? ? ? ?? ?????2.2.2:放在隐示的header消息中
2.1:直接定义在方法上:
? ? ?建工程名叫webservice06,在里面建一个包,在包里建一个实现类叫header_one,实现代码如下:
package sss.webservice;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import com.util.JdbcUtil;

public class Header_One {
public static Map<String,String> systemMap = new HashMap<String,String>();

static {
systemMap.put("OA","222221");
systemMap.put("CRM","222222");
systemMap.put("ERP","33333");
}

public String login(String username,String password,
String systemIdentity,String systemToken) {
if ((systemIdentity == null || systemIdentity.equals(""))
|| (systemToken == null || systemToken.equals(""))) {
throw new RuntimeException("服务端异常:系统标识与系统令牌不能为空 ");
} else {
if (systemMap.containsKey(systemIdentity) == false) {
throw new RuntimeException("服务端异常:没有该系统标识 ");
} else {
String tempToken = systemMap.get(systemIdentity);
if (systemToken.equals(tempToken) == false) {
throw new RuntimeException("服务端异常:令牌与系统不匹配 ");
} else {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = null;
Map<String,Object> jsonMap = new HashMap<String,Object>();
try {
sql = "Select user_name,user_pw From T_user where user_name = ?";
conn = JdbcUtil.getConnection();
stmt = conn.prepareStatement(sql);
stmt.setString(1,username);
rs = stmt.executeQuery();
if (rs.next()) {
String db_password = rs.getString("user_pw");

if (password.equals(db_password)) {
jsonMap.put("flag",true);
} else {
jsonMap.put("flag",false);
jsonMap.put("errorMsg","密码不正确");
}
} else {
jsonMap.put("flag","用户名不正确");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("服务端异常 = " + e.getMessage());
} finally {

}
Gson gson = new Gson();
String jsonStr = gson.toJson(jsonMap);
return jsonStr;
}
}
}
}
}

然后按照上面的方法二,在web工程中结合webservice的方法写好服务端。在客户端呢,就利用wsdl地址来生成客户端,并写测试类就好了。
服务端接口:
package com.webservice;

import javax.jws.WebParam;
import javax.jws.WebResult;

@javax.jws.WebService(targetNamespace = "http://webservice.com/",serviceName = "Header_OneService",portName = "Header_OnePort")
public class Header_OneDelegate {

com.webservice.Header_One header_One = new com.webservice.Header_One();

@WebResult(name = "loginResult")
public String login(@WebParam(name = "username")
String username,@WebParam(name = "password")
String password,@WebParam(name = "systemIdentity")
String systemIdentity,@WebParam(name = "systemToken")
String systemToken) {
return header_One
.login(username,password,systemIdentity,systemToken);
}
}
客户端测试:
package com.webservice_client.header_one;

import javax.xml.ws.soap.SOAPFaultException;

public class TestMain {
public static void main(String[] args) {
HeaderOneDelegate headerOne = new HeaderOneService().getHeaderOnePort();
try {
String jsonStr = headerOne.login("admin","123","OA","222221");
System.out.println(jsonStr);
} catch (SOAPFaultException e) {
System.out.println(e.getMessage());
}

}
}

?2.2.1:放在显示的header消息中
服务端的实现类和上面的Header_One是一样的,生成的接口类也是一样的,只是在参数要放在header里的@webparam里加了Header = true;代码如下:
public class Header_TwoDelegate {

com.webservice.Header_Two header_Two = new com.webservice.Header_Two();

@WebResult(name = "loginResult")
public String login(@WebParam(name = "username")
String username,@WebParam(name = "password")
String password,@WebParam(name = "systemIdentity",header = true)
String systemIdentity,@WebParam(name = "systemToken",header = true)
String systemToken) {
return header_Two
.login(username,systemToken);
}

}
然后发布和客户端生成,都和上面的是一样的。只是测试类有所不同:
package com.webservice_client.header_two;
//客户端测试类
public class TestMain {
public static void main(String[] args) {
HeaderTwoDelegate twoService = new HeaderTwoService()
.getHeaderTwoPort();

Login parameters = new Login();
parameters.setUsername("admin");
parameters.setPassword("123");
LoginResponse loginResponse = twoService.login(parameters,"CRM",
"222222");
String jsonStr = loginResponse.loginResult;
System.out.println(jsonStr);
}
}

此外,生成的wsdl文件也有不同之处,详情请自己去比较吧!
?2.2.2:放在隐示的header消息中:
? ? ?2.2.2.1在此之前先讲一个 Handler的建立与使用(与过滤器和监听器类似)。
? ? ?步骤:在上面的工程中,新建一个包叫com.webservice.handler,在里面建一个 PrintMessageHandler类,这个类得实现SOAPHandler<SOAPMessageContext>接口,重载它的方法。代码如下:
package com.webservice.handler;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;

import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;


public class PrintMessageHandler implements SOAPHandler<SOAPMessageContext> {
public Set<QName> getHeaders() {
System.out.println("getHeaders方法...");
return null;
}

public void close(MessageContext arg0) {
System.out.println("close方法...");
}

public boolean handleFault(SOAPMessageContext arg0) {
System.out.println("handleFault方法...");
return false;
}

public boolean handleMessage(SOAPMessageContext context) {

? System.out.println("handleMessage方法....");
return false;
}

}

然后写一个名叫server_chain.xml的东西,里面的内容为
<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>
? com.webservice.handler.PrintMessageHandler
</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
最后服务端要用这个处理类,就在接口类前写上@HandlerChain(file = "../../server_chain.xml")。客户端要用处理类,就得把这个写在实现类前。
?2.2.2.2:
package com.webservice;
//实现类,和前面的是一样的。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import com.util.JdbcUtil;

public class Header_Three {
public String login_xx(String username,String password) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = null;
Map<String,Object>();
try {
sql = "Select username,password From T_Userinfo where username = ?";
conn = JdbcUtil.getConn();
stmt = conn.prepareStatement(sql);
stmt.setString(1,username);
rs = stmt.executeQuery();
if (rs.next()) {
String db_password = rs.getString("password");

if (password.equals(db_password)) {
jsonMap.put("flag",true);
} else {
jsonMap.put("flag",false);
jsonMap.put("errorMsg","密码不正确");
}
} else {
jsonMap.put("flag","用户名不正确");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("服务端异常 = " + e.getMessage());
} finally {
JdbcUtil.closeResource(rs,stmt,conn);
}
Gson gson = new Gson();
String jsonStr = gson.toJson(jsonMap);
return jsonStr;
}

}

生成的webservice是:因为要用到处理类,所有手动加了 @HandlerChain(file = "../../server_chain.xml")
package com.webservice;

import javax.jws.HandlerChain;
import javax.jws.WebParam;

@javax.jws.WebService(targetNamespace = "http://webservice.com/",serviceName = "Header_ThreeService",portName = "Header_ThreePort")
@HandlerChain(file = "../../server_chain.xml")
public class Header_ThreeDelegate {
com.webservice.Header_Three header_Three = new com.webservice.Header_Three();

public String login_xx(@WebParam(name = "username")
String username,@WebParam(name = "password")
String password) {
return header_Three.login_xx(username,password);
}
}
服务端处理类的代码:
package com.webservice.handler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.rpc.soap.SOAPFaultException;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class PrintMessageHandler implements SOAPHandler<SOAPMessageContext> {

public static Map<String,"33333");
}

public Set<QName> getHeaders() {
System.out.println("getHeaders方法...");
return null;
}

public void close(MessageContext arg0) {
System.out.println("close方法...");
}

public boolean handleFault(SOAPMessageContext arg0) {
System.out.println("handleFault方法...");
return false;
}

public boolean handleMessage(SOAPMessageContext context) {
System.out.println("handleMessage方法...");

Boolean is_out = (Boolean) context
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (is_out == true) {
System.out.println("服务端返回消息:");
} else {
System.out.println("服务端接收消息:");
}

SOAPMessage message = context.getMessage();

try {
message.writeTo(System.out);

System.out.println("");
System.out.println("");
System.out.println("");
} catch (Exception e) {
e.printStackTrace();
}

/**
* 处理消息
*/
if (is_out == false) {
SOAPEnvelope envelope;
try {
envelope = message.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
SOAPBody body = envelope.getBody();
SOAPFault fault = body.getFault();
if (fault == null) {
fault = body.addFault();
}

System.out.println(header);
NodeList nodeList = header.getElementsByTagName("checkinfo");
if (nodeList == null || nodeList.getLength() == 0) {
System.out.println("checkinfo为空");
fault.setFaultCode("500");
fault.setFaultString("Header中的checkinfo节点为空值");
throw new javax.xml.ws.soap.SOAPFaultException(fault);
} else {
Element checkinfo = (Element) nodeList.item(0);
String systemIdentity = checkinfo.getElementsByTagName(
"systemIdentity").item(0).getFirstChild()
.getNodeValue();
String systemToken = checkinfo.getElementsByTagName(
"systemToken").item(0).getFirstChild()
.getNodeValue();

System.out.println("systemIdentity = " + systemIdentity);

System.out.println("systemToken = " + systemToken);

if (systemMap.containsKey(systemIdentity) == false) {
fault.setFaultCode("500");
fault.setFaultString("checkinfo中systemIdentity不正确");
throw new javax.xml.ws.soap.SOAPFaultException(fault);
} else {
String db_value = systemMap.get(systemIdentity);
if (db_value.equals(systemToken) == false) {
fault.setFaultCode("500");
fault.setFaultString("checkinfo中验证令牌不正确");
throw new javax.xml.ws.soap.SOAPFaultException(
fault);
} else {
return true;
}

}
}
} catch (SOAPException e) {
e.printStackTrace();
}
}

return true;
}

}

客户端:
测试类代码:
package com.webservice_client.header_three;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import sun.awt.windows.ThemeReader;

public class TestMain {
public static void main(String[] args) {
// TestMain.HttpClient_SendHeader();

TestMain.ClientStub_SendHeader();
}

/**
* 通过客户端桩的方式来发送,这时就需要用到ClientHeaderChain这个处理链
*/
private static void ClientStub_SendHeader() {
HeaderThreeDelegate threeService = new HeaderThreeService()
.getHeaderThreePort();

String jsonStr = threeService.loginXx("admin","123");

System.out.println(jsonStr);

}

/**
* 通过HttpClient来发送Soap中的Header消息
*/
private static void HttpClient_SendHeader() {

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(
"http://localhost:8080/WebService_Server_06/Header_ThreeService?wsdl");

try {

StringBuffer soapXML = new StringBuffer();
soapXML
.append("<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservice.com/">");
soapXML.append("<soapenv:Header>");

soapXML.append("<checkinfo>");
soapXML.append("<systemIdentity>OA</systemIdentity>");
soapXML.append("<systemToken>222221</systemToken>");
soapXML.append("</checkinfo>");
soapXML.append("</soapenv:Header>");

soapXML.append("<soapenv:Body>");
soapXML.append("<web:login_xx>");
soapXML.append("<username>admin</username>");
soapXML.append("<password>1111</password>");
soapXML.append("</web:login_xx>");

soapXML.append("</soapenv:Body>");
soapXML.append("</soapenv:Envelope>");

StringEntity soapEntity = new StringEntity(soapXML.toString());
httpPost.setEntity(soapEntity);
httpPost.setHeader("Content-Type","text/xml; charset=UTF-8");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String str = EntityUtils.toString(entity);

System.out.println("str = " + str);

if (str.indexOf("<faultcode>") != -1) {
/**
* 说明有错误消息
*/

String faultcode = str.substring(
str.indexOf("<faultcode>") + 11,str
.indexOf("</faultcode>"));

String faultstring = str.substring(
str.indexOf("<faultstring>") + 13,str
.indexOf("</faultstring>"));

System.out.println("faultCoe = " + faultcode);
System.out.println("faultstring = " + faultstring);
} else {
/**
* 正确
*/

String result = str.substring(str.indexOf("<return") + 17,str
.indexOf("</return>"));

System.out.println("result = " + result);
}

} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

客户端用到的处理类代码:建处理类的步骤如上。
package com.webservice_client.header_three;

import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class ClientHeaderChain implements SOAPHandler<SOAPMessageContext> {
/**
* 客户端要加入checkinfo的头部消息,供服务端解析
*/
public boolean handleMessage(SOAPMessageContext context) {
Boolean is_out = (Boolean) context
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (is_out == true) {
/**
* 加入Header消息
*/
SOAPMessage message = context.getMessage();
try {
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
SOAPHeader header = envelope.getHeader();
if (header == null) {
header = envelope.addHeader();
}
QName checkinfo = new QName("http://webservice.com/",
"checkinfo");
SOAPHeaderElement checkInfoElement = header
.addHeaderElement(checkinfo);
checkInfoElement.addChildElement("systemIdentity").setValue(
"CRM");
checkInfoElement.addChildElement("systemToken").setValue("222222");

} catch (SOAPException e) {
e.printStackTrace();
}
}
return true;
}

public Set<QName> getHeaders() {
return null;
}

public void close(MessageContext arg0) {
}

public boolean handleFault(SOAPMessageContext arg0) {
// TODO Auto-generated method stub
return false;
}

}

注意点:
? ? ?比较合理的方式。通过SoapHandler来传递与接收头部消息。
?????抛异常不能使用throw new RuntimeException的方式,要使用throw new SOAPFaultException(fault);
? ?? 从服务端角度看:inbound表示接收客户端消息,outbound表示响应消息给客户端..从客户端角度看时正好与之相反

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读