Apache CXF实战之6 创建安全的Web Service
Apache CXF实战之六 创建安全的Web Service我们在使用Web Service的过程中,很多情况是需要对web service请
Apache CXF实战之六 创建安全的Web Service
我们在使用Web Service的过程中,很多情况是需要对web service请求做认证的,对于运行在web容器里的应用程序来说,可能会比较简单一些,通常可以通过filter来做一些处理,但是其实CXF本身也提供了对web service认证的方式。下面来看一下如何实现
1. 首先是一个简单pojo
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- public?class?User?{??
- ????private?String?id;??
- ????private?String?name;??
- ????private?String?password;??
- ????public?String?getId()?{??
- ????????return?id;??
- ????}??
- ????public?void?setId(String?id)?{??
- ????????this.id?=?id;??
- ????}??
- ????public?String?getName()?{??
- ????????return?name;??
- ????}??
- ????public?void?setName(String?name)?{??
- ????????this.name?=?name;??
- ????}??
- ????public?String?getPassword()?{??
- ????????return?password;??
- ????}??
- ????public?void?setPassword(String?password)?{??
- ????????this.password?=?password;??
- ????}??
- }??
2. Web Service接口
?
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- import?java.util.List;??
- ??
- import?javax.jws.WebMethod;??
- import?javax.jws.WebResult;??
- import?javax.jws.WebService;??
- ??
- @WebService??
- public?interface?UserService?{??
- ????@WebMethod??
- ????@WebResult?List<User>?list();??
- ??
- }??
3. Web Service实现类
?
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- import?java.util.ArrayList;??
- import?java.util.List;??
- ??
- public?class?UserServiceImpl?implements?UserService?{??
- ??
- ????public?List<User>?list()?{??
- ????????List<User>?users?=?new?ArrayList<User>();??
- ????????for?(int?i?=?0;?i?<?10;?i++)?{??
- ????????????User?user?=?new?User();??
- ????????????user.setId(""?+?i);??
- ????????????user.setName("user_"?+?i);??
- ????????????user.setPassword("password_"?+?i);??
- ????????????users.add(user);??
- ????????}??
- ????????return?users;??
- ????}??
- ??
- }??
4. Server端Handler,其中使用了一个Map来存放用户信息,真是应用中可以使用数据库或者其它方式获取用户和密码
?
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- 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.ws.security.WSPasswordCallback;??
- ??
- public?class?ServerUsernamePasswordHandler?implements?CallbackHandler?{??
- ??
- ????//?key?is?username,?value?is?password??
- ????private?Map<String,?String>?users;??
- ??
- ????public?ServerUsernamePasswordHandler()?{??
- ????????users?=?new?HashMap<String,?String>();??
- ????????users.put("admin",?"admin");??
- ????}??
- ??
- ????public?void?handle(Callback[]?callbacks)?throws?IOException,?UnsupportedCallbackException?{??
- ????????WSPasswordCallback?callback?=?(WSPasswordCallback)?callbacks[0];??
- ????????String?id?=?callback.getIdentifier();??
- ????????if?(users.containsKey(id))?{??
- ????????????if?(!callback.getPassword().equals(users.get(id)))?{??
- ????????????????throw?new?SecurityException("Incorrect?password.");??
- ????????????}??
- ????????}?else?{??
- ????????????throw?new?SecurityException("Invalid?user.");??
- ????????}??
- ????}??
- }??
5. Client端Handler,用来设置用户密码,在真实应用中可以根据此类和下面的测试类来修改逻辑设置用户名和密码。
?
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- 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?ClientUsernamePasswordHandler?implements?CallbackHandler?{??
- ????public?void?handle(Callback[]?callbacks)?throws?IOException,?UnsupportedCallbackException?{??
- ????????WSPasswordCallback?callback?=?(WSPasswordCallback)?callbacks[0];??
- ????????int?usage?=?callback.getUsage();??
- ????????System.out.println("identifier:?"?+?callback.getIdentifier());??
- ????????System.out.println("usage:?"?+?callback.getUsage());??
- ????????if?(usage?==?WSPasswordCallback.USERNAME_TOKEN)?{??
- ????????????callback.setPassword("admin");??
- ????????}??
- ????}??
- }??
6. 单元测试类,注意在Server端添加了WSS4JInInterceptor到Interceptor列表中,在Client添加了WSS4JOutInterceptor到Interceptor列表中。
?
?
[java]?view plaincopyprint??
- package?com.googlecode.garbagecan.cxfstudy.security;??
- ??
- import?java.net.SocketTimeoutException;??
- import?java.util.HashMap;??
- import?java.util.List;??
- import?java.util.Map;??
- ??
- import?javax.xml.ws.WebServiceException;??
- ??
- import?junit.framework.Assert;??
- ??
- import?org.apache.cxf.endpoint.Client;??
- import?org.apache.cxf.endpoint.Endpoint;??
- import?org.apache.cxf.frontend.ClientProxy;??
- import?org.apache.cxf.interceptor.LoggingInInterceptor;??
- import?org.apache.cxf.interceptor.LoggingOutInterceptor;??
- import?org.apache.cxf.jaxws.JaxWsProxyFactoryBean;??
- import?org.apache.cxf.jaxws.JaxWsServerFactoryBean;??
- import?org.apache.cxf.transport.http.HTTPConduit;??
- import?org.apache.cxf.transports.http.configuration.HTTPClientPolicy;??
- import?org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;??
- import?org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;??
- import?org.apache.ws.security.WSConstants;??
- import?org.apache.ws.security.handler.WSHandlerConstants;??
- import?org.junit.BeforeClass;??
- import?org.junit.Test;??
- ??
- public?class?UserServiceTest?{??
- ??
- ????private?static?final?String?address?=?"http://localhost:9000/ws/security/userService";??
- ??????
- ????@BeforeClass??
- ????public?static?void?setUpBeforeClass()?throws?Exception?{??
- ????????JaxWsServerFactoryBean?factoryBean?=?new?JaxWsServerFactoryBean();??
- ????????factoryBean.getInInterceptors().add(new?LoggingInInterceptor());??
- ????????factoryBean.getOutInterceptors().add(new?LoggingOutInterceptor());??
- ??
- ????????Map<String,?Object>?props?=?new?HashMap<String,?Object>();??
- ????????props.put("action",?"UsernameToken");??
- ????????props.put("passwordType",?"PasswordText");??
- ????????props.put("passwordCallbackClass",?ServerUsernamePasswordHandler.class.getName());??
- ????????WSS4JInInterceptor?wss4JInInterceptor?=?new?WSS4JInInterceptor(props);??
- ????????factoryBean.getInInterceptors().add(wss4JInInterceptor);??
- ??????????
- ????????factoryBean.setServiceClass(UserServiceImpl.class);??
- ????????factoryBean.setAddress(address);??
- ????????factoryBean.create();??
- ????}??
- ??
- ????@Test??
- ????public?void?testList()?{??
- ????????JaxWsProxyFactoryBean?factoryBean?=?new?JaxWsProxyFactoryBean();??
- ????????factoryBean.setAddress(address);??
- ????????factoryBean.setServiceClass(UserService.class);??
- ????????Object?obj?=?factoryBean.create();??
- ??????????
- ????????Client?client?=?ClientProxy.getClient(obj);??
- ????????Endpoint?endpoint?=?client.getEndpoint();??
- ??????????
- ????????Map<String,Object>?props?=?new?HashMap<String,Object>();??
- ????????props.put(WSHandlerConstants.ACTION,?WSHandlerConstants.USERNAME_TOKEN);??
- ????????props.put(WSHandlerConstants.USER,?"admin");??
- ????????props.put(WSHandlerConstants.PASSWORD_TYPE,?WSConstants.PW_TEXT);??
- ????????props.put(WSHandlerConstants.PW_CALLBACK_CLASS,?ClientUsernamePasswordHandler.class.getName());??
- ????????WSS4JOutInterceptor?wss4JOutInterceptor?=?new?WSS4JOutInterceptor(props);??
- ????????endpoint.getOutInterceptors().add(wss4JOutInterceptor);??
- ??????????
- ????????HTTPConduit?conduit?=?(HTTPConduit)?client.getConduit();??
- ????????HTTPClientPolicy?policy?=?new?HTTPClientPolicy();??
- ????????policy.setConnectionTimeout(5?*?1000);??
- ????????policy.setReceiveTimeout(5?*?1000);??
- ????????conduit.setClient(policy);??
- ??????????
- ????????UserService?service?=?(UserService)?obj;??
- ????????try?{??
- ????????????List<User>?users?=?service.list();??
- ????????????Assert.assertNotNull(users);??
- ????????????Assert.assertEquals(10,?users.size());??
- ????????}?catch(Exception?e)?{??
- ????????????if?(e?instanceof?WebServiceException???
- ????????????????????&&?e.getCause()?instanceof?SocketTimeoutException)?{??
- ????????????????System.err.println("This?is?timeout?exception.");??
- ????????????}?else?{??
- ????????????????e.printStackTrace();??
- ????????????}??
- ????????}??
- ????}??
- ??
- }??
最后运行上面的测试类来测试结果,也可以修改测试方法中的密码,看看错误结果,这里就不在写错误密码的测试用例了,因为我是一懒人。