(十三)使用handler实现登录验证
一、Handel概念
-
J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个HTTP到达服务端时,往往要经过多个Filter对请求进行过滤,然后才到达提供服务的Servlet,这些Filter的功能往往是对请求进行统一编码,对用户进行认证,把用户的访问写入系统日志等。相应的,Web服务中的Handler通常也提供一下的功能:
- 对客户端进行认证、授权;
- 把用户的访问写入系统日志;
- 对请求的SOAP消息进行加密,解密;
- 为Web Services对象做缓存。
SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可以在客户端使用。 -
handler可以作用于客户端,也可以作用了服务端
handler分为:1、LogicalHandler:只能获取到soap消息的body。
2、SOAPHandler:可以获取SOAPMessage的信息(我们通常用这种)。
-
客户端--》服务端的请求中通过handler的顺序:
假如客户端和服务端的handler-chain.xml中定义的顺序都是:LogicalHandler1/SOAPHandler1/LogicalHandler2/SOAPHandler2
那么请求的顺序将是:
client-->LogicalHandler1-->LogicalHandler2-->SOAPHandler1-->SOAPHandler2-->|服务器容器|-->SOAPHandler1-->SOAPHandler2-->LogicalHandler1-->LogicalHandler2-->service
二、案例
- 效果: 客户端在调用服务端的时候,传过去用户名和密码,服务端判断用户名和密码是否正确。
-
服务端
2.1 编写服务接口和实现类
package services; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService public interface ILogin { @WebResult(name="loginResult") public String login(@WebParam(name="userName")String userName,@WebParam(name="passWord")String passWord); }
package services; import javax.jws.HandlerChain; import javax.jws.WebService; @WebService(endpointInterface = "services.ILogin") @HandlerChain(file = "handler-chain.xml") public class LoginImpl implements ILogin { @Override public String login(String userName, String passWord) { return "welcome " + userName; } }
-
@HandlerChain(file = "handler-chain.xml") 要配置,该注解指定了某个服务要执行的handleChain
2.2 编写Handle
package com.handler; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class LoginHandler implements SOAPHandler<SOAPMessageContext> { @Override public boolean handleMessage(SOAPMessageContext context) { System.out.println("run handleMessage method"); Boolean out = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY); if (!out) { try { SOAPMessage message = context.getMessage(); SOAPPart part = message.getSOAPPart(); SOAPEnvelope envelope = part.getEnvelope(); SOAPBody body = envelope.getBody(); String userName = body.getElementsByTagName("userName").item(0).getTextContent(); String passWord = body.getElementsByTagName("passWord").item(0).getTextContent(); if (userName.equals("admin")) { if (passWord.equals("123")) { // 正确 return true; } else { throw new RuntimeException("密码错误或者为空"); } } else { throw new RuntimeException("用户名错误或者为空"); } } catch (Exception e) { e.printStackTrace(); return false; } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { System.out.println("run handleFault method"); return false; } @Override public void close(MessageContext context) { System.out.println("run close method"); } @Override public Set<QName> getHeaders() { System.out.println("run getHeaders method"); return null; } }
- 如果handleMessage方法返回的是false,那么客户端收到的便是发送的soap消息(发送的soap消息,接收的也是这个消息),如果是返回true,则正确调用服务端的方法。
2.3 编写handler-chain.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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.handler.LoginHandler </javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
2.4 发布服务
package publish; import javax.xml.ws.Endpoint; import services.LoginImpl; public class publish { public static void main(String[] args) { Endpoint.publish("http://localhost:8081/login", new LoginImpl()); System.out.println("服务启动成功......"); } }
-
客户端
2.5 测试
package testMain; import java.io.StringReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; 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 org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class TestMain { public static void main(String[] args) { try { /** * 定义发送soap的消息 */ StringBuffer str_xml = new StringBuffer(); str_xml.append( " <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://services/\">"); str_xml.append(" <soapenv:Header/>"); str_xml.append(" <soapenv:Body>"); str_xml.append("<ser:login>"); str_xml.append(" <userName>admin</userName>"); str_xml.append("<passWord>123</passWord>"); str_xml.append("</ser:login>"); str_xml.append(" </soapenv:Body>"); str_xml.append(" </soapenv:Envelope>"); /** * 定义post请求 */ // 定义post请求地址 HttpPost httpPost = new HttpPost("http://localhost:8081/login?wsdl"); // 定义post请求的实体 HttpEntity entity = new StringEntity(str_xml.toString()); // 设置post请求的实体和头部 httpPost.setEntity(entity); httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8"); /** * 发送请求并获取返回数据 */ @SuppressWarnings("deprecation") DefaultHttpClient client = new DefaultHttpClient(); // 发送请求并获取返回数据 HttpResponse response = client.execute(httpPost); // 获取返回数据中的实体 HttpEntity respon_entity = response.getEntity(); // 将返回数据的实体转为字符串 String respon_str = EntityUtils.toString(respon_entity); // 解析字符串 SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(respon_str)); Element rootElement = document.getRootElement(); Element resultElement = rootElement.element("Body").element("loginResponse").element("loginResult"); String addResult = resultElement.getText(); System.out.println("loginResult = " + addResult); } catch (Exception e) { e.printStackTrace(); } } }
2.6 结果
用户名密码正确,成功调用服务端方法。