With the previous article, I'm sure you've learned how to use CXF to develop SOAP based WS. Perhaps you are not very understanding of the underlying original reason, there will be some doubt in your mind:
What is WSDL.
What is SOAP.
How to make SOAP more secure.
I will try to get a satisfactory answer to the above questions through this article.
What are you waiting for? Let's start with the WSDL.
The full name of the WSDL is the Web Services Description Language (Web Service Description Language), which describes the specific content of WS.
When you successfully publish a WS, you can view the WSDL document in a browser from a single address, which is an xml-based document. A typical WSDL address is as follows:
http://localhost:8080/ws/soap/hello?wsdl
Note: The WSDL address must be provided with a WSDL parameter.
In the browser, you will see a standard XML document:
Where definitions is the root node of the WSDL, it includes two important attributes: Name:ws name, default to "WS implementation class + Service", for example: Helloserviceimplservice targetnamespace:ws The target namespace, which defaults to "the address of the WS implementation class corresponding to the package name inverted", for example: http://soap_spring_cxf.ws.demo/
Tip: You can configure the above two property values in the Javax.jws.WebService annotation, but this configuration must be done on the WS implementation class, and the WS interface class simply needs to mark a WebService annotation.
Under the root node of definitions, there are five types of child nodes: types: Describes the data types involved in WS PortType: The WS Interface Name (ENDPOINTINTERFACE) and its operation name are defined. and input and output message messages for each operation: the related message is defined (for types and PortType) binding: Provides data binding to WS Service:ws name and its port name (PortName), and corresponding WSDL Address
This includes two important information: the port name of the PORTNAME:WS, the default is "WS implementation class + port", for example: Helloserviceimplport ENDPOINTINTERFACE:WS Interface Name, defaults to "the interface implemented by the WS implementation Class" , such as: HelloService
Tip: PortName and Endpointinterface can be configured in the Javax.jws.WebService annotation, and must also be configured on the WS implementation class.
If WSDL is used to describe what WS is, then SOAP is used to represent what is in WS.
In fact, SOAP is an envelope (Envelope), in which there are two parts, one is head (header) and the other is body. The data used for transmission is placed in the body, and some special attributes need to be placed in the Header (see below).
In general, the data that needs to be transferred is placed in the body, and the Header is not content, and it looks like the entire SOAP message is:
As you can see, the request Header for HTTP requests and the request body are just as good as the structure of the SOAP message.
See here, you may have a lot of questions: WS should not let anyone can call, this is too unsafe, at least need to do an identity authentication bar. In order to avoid third-party malicious programs monitoring the WS invocation process, can you encrypt the data in the SOAP body? What can be stored in the SOAP Header?
That's right. That's the topic we're going to start today--SOAP based security control.
In the WS domain has a very strong solution, called ws-security, it is only a specification, in the Java industry has a very authoritative implementation, named Wss4j.
Here's a step-by-step lesson to learn how to implement a secure WS invoke framework using Spring + CXF + wss4j.
In fact, you need to do two things: Authentication WS request Encryption SOAP message
How to authenticate WS. The following solutions are available: 1. Identity authentication based on user's token
Step one: Add the ws-security Maven dependencies provided by CXF
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactid>cxf-rt-ws-security </artifactId>
<version>${cxf.version}</version>
</dependency>
In fact, the bottom of the implementation or WSS4J,CXF just to do a package.
Step Two: Complete the service-side CXF related configuration
<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:x Si= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf= "Http://cxf.apache.org/core" xmlns:jaxws= "HTTP://CX" F.apache.org/jaxws "xsi:schemalocation=" Http://www.springframework.org/schema/beans Http://www.springframewo
Rk.org/schema/beans/spring-beans-4.0.xsd Http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd Http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd "> <bean id=" wss4jininterceptor
"class=" Org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor "> <constructor-arg> <map>
<!--user authentication (plaintext password)--> <entry key= "action" value= "UsernameToken"/> <entry key= "Passwordtype" value= "Passwordtext"/> <entry key= "passwordcallbackref" value-ref= "se Rverpasswordcallback "/> </map> </constructor-arg> </bean> <jaxws:endpoint id= "HelloService" implementor= "#he Lloserviceimpl "address="/soap/hello "> <jaxws:inInterceptors> <ref bean=" Wss4jinintercepto R "/> </jaxws:inInterceptors> </jaxws:endpoint> <cxf:bus> <cxf:features>
;
<cxf:logging/> </cxf:features> </cxf:bus> </beans>
First, we define a wss4j interceptor (Wss4jininterceptor), and then configure it to the HelloService, and finally use the bus features provided by CXF, you can only configure a logging on the bus. Monitor the log of each WS request and response.
Note: This wss4jininterceptor is a ininterceptor that intercepts incoming messages, as well as outinterceptor, which means blocking messages from the output. As the above is the server-side configuration, so we only need to configure Ininterceptor, for the client, we can configure Outinterceptor (see below).
It is necessary to make a description of the constructor parameters for Wss4jininterceptor in the above configuration. Action = UsernameToken: Represents authentication using a "username token" Passwordtype = Passwordtext: Indicates that the password appears in plaintext Passwordcallbackref = Serverpasswordcallback: Need to provide a callback processor for password verification (CallbackHandler)
The following are the specific implementations of Serverpasswordcallback:
Package demo.ws.soap_spring_cxf_wss4j;
Import java.io.IOException;
Import Java.util.HashMap;
Import Java.util.Map;
Import Javax.security.auth.callback.Callback;
Import Javax.security.auth.callback.CallbackHandler;
Import javax.security.auth.callback.UnsupportedCallbackException;
Import Org.apache.wss4j.common.ext.WSPasswordCallback;
Import org.springframework.stereotype.Component; @Component public class Serverpasswordcallback implements CallbackHandler {private static final map<string, Strin
g> UserMap = new hashmap<string, string> ();
static {Usermap.put ("client", "Clientpass");
Usermap.put ("Server", "Serverpass"); @Override public void handle (callback[] callbacks) throws IOException, unsupportedcallbackexception {W
Spasswordcallback callback = (wspasswordcallback) callbacks[0];
String clientusername = Callback.getidentifier ();
String Serverpassword = Usermap.get (clientusername); if (SERVERPASSWOrd!= null) {Callback.setpassword (Serverpassword);
}
}
}
Visible, it implements the Javax.security.auth.callback.CallbackHandler interface, which is a callback processor interface for security authentication provided by the JDK. Two users are provided in the code, client and server, and username and password are stored in UserMap. There is a need to transform the javax.security.auth.callback.Callback provided by JDK into the org.apache.wss4j.common.ext.WSPasswordCallback provided by WSS4J, The handle method implements the validation of the client's password, which ultimately requires the password to be placed in the callback object.
Step three: Complete the client CXF related configuration
<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns=
"Http://www.springframework.org/schema/beans"
xmlns:xsi= "Http://www.w3.org/2001/XMLSchema-instance"