基于CXF的webservice的鉴权

参照上一篇博文 基于HTTPS的webservice 的环境搭建step by step 完成所需环境之后,就可以开始接下来的著名项目HelloWorld了。
1.    建立一个helloworld的web项目
2.    创建SEI

package com.harvey.services;

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

@WebService(targetNamespace="http://webservice.harvey.com")
public interface HelloWorldInf {
	public String sayHello(@WebParam(name="name")String name);
}

 通过@WebService注解将该接口声明为webservice

3.    创建SIB

package com.harvey.services;

import javax.jws.WebService;

@WebService(endpointInterface="com.harvey.services.HelloWorldInf",
targetNamespace="http://webservice.harvey.com")
public class HelloWorldImpl implements HelloWorldInf {
	public String sayHello(String name) {
		return "hello,"+name;
	}
}

 这个类功能虽然很强大,但是应该比较容易看懂,就是向调用者打招呼。

4.    建立鉴权的handler

package com.harvey.services;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class ServerPasswordCallback implements CallbackHandler {

	public void handle(Callback[] callbacks) throws IOException,
			UnsupportedCallbackException {
		WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
		String pw = pc.getPassword();
		String idf = pc.getIdentifier(); 
		
		if (!"harvey".equals(idf) || !"123456".equals(pw)) {
			throw new SecurityException("鉴权失败!");
		}
	}

}

 5.    通过spring整合
通过spring发布helloworld服务并为服务添加鉴权的handler.
在web.xml的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<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>

	 <servlet>
	 	<servlet-name>CXFServlet</servlet-name>
	 	<servlet-class>
	 		org.apache.cxf.transport.servlet.CXFServlet
	 	</servlet-class>
	 	<load-on-startup>1</load-on-startup>
	 </servlet>

	 <servlet-mapping>
	 	<servlet-name>CXFServlet</servlet-name>
	 	<url-pattern>/services/*</url-pattern>
	 </servlet-mapping>
	 <welcome-file-list>
	 	<welcome-file>index.jsp</welcome-file>
	 </welcome-file-list>
</web-app>

 为了方便直接在src目录下建立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:aop="http://www.springframework.org/schema/aop"
	xmlns:cxf="http://cxf.apache.org/core"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
	
	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://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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" /> 
	<bean id="hello" class="com.harvey.services.HelloWorldImpl" />
	<jaxws:endpoint  id="helloworldservice" 
		endpointName="e:helloWorldPointName" 
		serviceName="s:helloworldservice" 
		implementor="#hello"  
		address="/helloworld"
		xmlns:e="http://webservice.harvey.com/endponit"
		xmlns:s="http://webservice.harvey.com/service">
		
		<jaxws:inInterceptors>  
             <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
                 <constructor-arg>  
                     <map>  
                         <entry key="action" value="UsernameToken" />  
                         <entry key="passwordType"  
                             value="PasswordText" />  
                         <entry key="user" value="cxfServer" />  
                         <entry key="passwordCallbackRef">  
                             <ref bean="serverPasswordCallback" />  
                         </entry>  
                     </map>  
                 </constructor-arg>  
             </bean>  
         </jaxws:inInterceptors>  
	</jaxws:endpoint>
	
	<bean id="serverPasswordCallback"   class="com.harvey.services.ServerPasswordCallback" />
</beans>

 Server端的工作就这些了,结合我们在上一篇文章中提到的数字证书的环境,一个支持数字证书和鉴权的server端搭建完成了。
接下来我们在转到client端,看一下如何在client加入对数字证书以及鉴权的支持。

 

6.    创建client端的密码的handler
为了方便起见,我们不再为client独立创建功能,与service在同一项目下建立client端的回调类,为webservice的请求添加鉴权的头信息

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class ClientPasswordCallback implements CallbackHandler {

	public void handle(Callback[] callbacks) throws IOException,
			UnsupportedCallbackException {
		WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        pc.setPassword("123456");
        pc.setIdentifier("Harvey");
	}

}

 

7.    创建client的spring配置文件

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:cxf="http://cxf.apache.org/core"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:http="http://cxf.apache.org/transports/http/configuration"
	xmlns:sec="http://cxf.apache.org/configuration/security"
	
	xsi:schemaLocation="
	http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd 
	http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd 
	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://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<bean id="client" class="com.harvey.services.HelloWorldInf"
		factory-bean="clientFactory" factory-method="create" />

	<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
		<property name="serviceClass" value="com.harvey.services.HelloWorldInf" />
		<property name="address" value="https://localhost:8443/WebServiceDemo/services/helloworld" />
         <property name="outInterceptors">  
             <list>  
                 <ref bean="wss4jOut" />  
             </list>  
         </property>  
	</bean>
	<bean id="wss4jOut" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
		<constructor-arg>
			<map>
				<entry key="action" value="UsernameToken" />
				<entry key="user" value="cxfClient" />
				<entry key="passwordType" value="PasswordText" />
				<entry key="passwordCallbackClass" value="com.harvey.services.ClientPasswordCallback" />
			</map>
		</constructor-arg>
	</bean>
</beans>

 8.    创建client端的测试类,并将上一篇 博文中生成的client.jks和truststore.jks添加到类目录下

package com.harvey.test;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.harvey.services.HelloWorldInf;

public class HelloWorldClient {
	private final static String trustStore = "truststore.jks";
	private final static String keyStore = "client.jks";
	private final static String trustStorePass = "123456";
	private final static String keyStorePass = "999999";
	
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		ApplicationContext context=new ClassPathXmlApplicationContext("client-bean.xml");
		HelloWorldInf client = (HelloWorldInf)context.getBean("client");
		
		Client proxy = ClientProxy.getClient(client);   
        HTTPConduit conduit = (HTTPConduit) proxy.getConduit();    
        TLSClientParameters tlsParams = conduit.getTlsClientParameters();
        
        if (tlsParams == null) {
            tlsParams = new TLSClientParameters();
        }
        tlsParams.setSecureSocketProtocol("SSL");
        tlsParams.setKeyManagers(getKeyManagers());
        tlsParams.setTrustManagers(getTrustManagers());
        conduit.setTlsClientParameters(tlsParams);
        
		String response = client.sayHello("han");
		System.out.println(response);
	}
	
	private static TrustManager[] getTrustManagers() throws IOException {
		try {
			String alg = TrustManagerFactory.getDefaultAlgorithm();
			TrustManagerFactory factory = TrustManagerFactory.getInstance(alg);
			InputStream fp = HelloWorldClient.class.getResourceAsStream(trustStore);
			KeyStore ks = KeyStore.getInstance("JKS");
			ks.load(fp, trustStorePass.toCharArray());
			fp.close();
			factory.init(ks);
			TrustManager[] tms = factory.getTrustManagers();
			return tms;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private static KeyManager[] getKeyManagers() throws IOException {
		try {
			String alg = KeyManagerFactory.getDefaultAlgorithm();
			KeyManagerFactory factory = KeyManagerFactory.getInstance(alg);
			InputStream fp = HelloWorldClient.class.getResourceAsStream(keyStore);
			KeyStore ks = KeyStore.getInstance("JKS");
			ks.load(fp, keyStorePass.toCharArray());
			fp.close();
			factory.init(ks, keyStorePass.toCharArray());
			KeyManager[] keyms = factory.getKeyManagers();
			return keyms;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) {
			e.printStackTrace();
		}
		return null;
	}
}

 

9.现在就可以运行client端测试鉴权功能了。
   
    本来想着认真解释一下代码,不过环境太吵,实在没法安静下来写,就算是抛砖引玉吧。

你可能感兴趣的:(apache,AOP,bean,webservice,Security)