首页 > 编程 > Java > 正文

Java WebService_cxf (2) 加密认证

2019-11-11 01:25:57
字体:
来源:转载
供稿:网友

我们创建的webService服务要有安全性,不能被人随便调用,要有用户认证,在传输过程中还要加密。

java WebService_cxf  (1) 入门案例 中的创建的服务任何人都可以调用,这显然是不安全的,我们在入门案例基础上加入用户的认证。

服务器端:

将sPRing-cxf-service.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:jaxws="http://cxf.apache.org/jaxws"       xsi:schemaLocation=" http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">    <import resource="classpath:META-INF/cxf/cxf.xml"/>    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>    <bean id="cxfDemoImple" class="shzj.web.webService.service.imple.CxfDemoImple"/>    <bean id="DemoServerPassWordCallback"  class="shzj.web.webService.service.DemoServerPasswordCallback"/>    <jaxws:endpoint id="hello" implementor="#cxfDemoImple" address="/helloWorld" >        <jaxws:inInterceptors>            <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />            <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="FHDClient" />                        <entry key="passwordCallbackRef">                            <ref bean="DemoServerPasswordCallback" />                        </entry>                    </map>                </constructor-arg>            </bean>        </jaxws:inInterceptors>    </jaxws:endpoint></beans >

密码回调函数类:

package shzj.web.webService.service;import org.apache.ws.security.WSPasswordCallback;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.UnsupportedCallbackException;import java.io.IOException;public class DemoServerPasswordCallback implements CallbackHandler {    public void handle(Callback[] callbacks) throws IOException,            UnsupportedCallbackException {        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];        String pw = pc.getPassword();        String idf = pc.getIdentifier();        //特别注意的是 这里的pw肯是null, 无论你password是否传值。cxf 2.4之后,        //密码的比较是框架自动帮我们完成,因此不需要我们获取传递过来的密码,如果你        //一定要查看密码的话,可以通过new String(pc.getKey())获取。在该回调函数中        //我们只需要使用 idf 从数据库中查询出密码,使用pc.setPassword()方法将密码设        //置进去,框架获取的的密码后会进行比较,并通过抛出异常的方式提示验证出错。        System.out.println("密码是: " + pw);        System.out.println("身份是: " + idf);        //根据idf 我们从数据中查询出的密码 假如是 "abc"        pc.setPassword("abc");    }}

发布

客户端使用wsimport在客户端生成本地服务类。替换原来的。

第一种实现方式:通过配置客户端来调用服务

spring-cxf-client.xml修改为:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:cxf="http://cxf.apache.org/core"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="          http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans.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="DemoClientPasswordCallback" class="shzj.web.webService.service.DemoClientPasswordCallback"/>    <jaxws:client id="DemoClient" serviceClass="com.demo.client.CxfDemo"                  address="http://localhost:8080/shzj/webservice/helloWorld?wsdl">        <jaxws:outInterceptors>            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>            <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">                <constructor-arg>                    <map>                        <entry key="action" value="UsernameToken"/>                        <entry key="passwordType" value="PasswordText"/>                        <entry key="user" value="FHDClient"/>                        <entry key="passwordCallbackRef">                            <ref bean="DemoClientPasswordCallback"/>                        </entry>                    </map>                </constructor-arg>            </bean>        </jaxws:outInterceptors>    </jaxws:client></beans>

密码回调函数类:

package shzj.web.webService.service;import org.apache.ws.security.WSPasswordCallback;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.UnsupportedCallbackException;import java.io.IOException;public class DemoClientPasswordCallback implements CallbackHandler {    public void handle(Callback[] callbacks) throws IOException,            UnsupportedCallbackException {        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];        String ident = "I";        String passwd = "2";        pc.setPassword(passwd);        pc.setIdentifier(ident);    }}

测试:

    @Test    public  void text2() {        applicationContext factory = new ClassPathXmlApplicationContext("/spring-cxf-client.xml");        CxfDemo client = (CxfDemo)factory.getBean("DemoClient");        String response = client.helloWord("小米");        System.out.println("返回: " + response);    }发送的数据为:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"                   xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"                   soap:mustUnderstand="1">        <wsse:UsernameToken wsu:Id="UsernameToken-794D515C6E4EAC356E14864531467091">            <wsse:Username>I</wsse:Username>            <wsse:Password                    Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">                2            </wsse:Password>        </wsse:UsernameToken>    </wsse:Security></SOAP-ENV:Header><soap:Body>    <ns2:helloWord xmlns:ns2="http://service.webService.web.shzj/">        <userName>小米</userName>    </ns2:helloWord></soap:Body></soap:Envelope>

结果:出现异常,javax.xml.ws.soap.SOAPFaultException: The security token could not be authenticated or authorized

很显然是认证出错了。应为密码出错。如果密码是abc,结果就是:返回: hello 小米!!!

cxf框架验证出错是通过抛出异常提示我们的,那么经常会抛出的异常有:

Fault from server : Missing wsse:Security in SOAP Header.Cause: This error is thrown by server if SOAP request does not contain a Web Service Security Header in SOAPHeader section of SOAPEnvelope.Resolution: Pass a valid Web Service Security Header, containing valid Username token, in SOAPHeader.(如果是SoapUI测试的话,也需要设置WSS-Password Type为PasswordText)Fault from server : Policy requires authentication token.Cause: This error is thrown by server when either Web Service Security Username Token in Security header is missing or is invalid.Resolution: Pass a valid Web Service Security Username Token in Security header.Fault from server : The security token could not be authenticated or authorizedCause: This error is thrown by server when username or(/and) password in Web Service Security Username Token is invalid.Resolution: Pass valid Oracle applications username and password in Web Service Security Username Token.Fault from server : User not authorized to execute serviceCause: This error is thrown by server when user given in Web Service Security Username Token is not authorized to execute the Web Service function being invoked in SOAP Request.Resolution: Create grant at user, role or global level from Integration Repository UI to authorize the the user to execute Web Service function. Clear cache from Functional Administrator Responsibility.Fault from server : Responsibility key is not validCause: This error is thrown by server when Responsibility Key passed in Responsibility Header in SOAHeader is invalid.Resolution: Server expects a valid Responsibility Key in Responsibility Header in SOAHeader.Use this query to find valid Responsibility Keys for a particular user:-Select resp.RESPONSIBILITY_KEY, grp.SECURITY_GROUP_KEY,APP.APPLICATION_SHORT_NAMEFrom FND_USER_RESP_GROUPS furg, FND_USER usr, fnd_responsibility_vlresp,FND_SECURITY_GROUPS grp,FND_APPLICATION APPwhere furg.user_id=usr.user_idand furg.RESPONSIBILITY_ID=resp.RESPONSIBILITY_IDand furg.SECURITY_GROUP_ID=grp.SECURITY_GROUP_IDand furg.RESPONSIBILITY_APPLICATION_ID=APP.APPLICATION_IDand usr.user_name= <username>Fault from server: Responsibility Application Short name is not valid.Cause: This error is thrown by server when Application Short name in RespApplication Header in SOAHeader is invalid.Resolution: Server expects a valid Application short name in RespApplication Header in SOAHeader. Use query given above to find a valid Application short name.Fault from server: Security Group Key is not valid.Cause: This error is thrown by server when Security Group Key in SecurityGroup Header in SOAHeader is invalid.Resolution: Server expects a valid Security Group Key in SecurityGroup Header in SOAHeader. Use query given above to find a valid Security Group Key.Fault from server: NLS Language is not valid.Cause: This error is thrown by server when NLS Language in NLSLanguage Header in SOAHeader is invalid.Resolution: Server expects a valid NLSLanguage value in NLSLanguage Header in SOAHeader. Use the following query to find a valid NLSLanguage:SELECT NLS_LANGUAGEFROM   FND_LANGUAGESWHERE  INSTALLED_FLAG in (‘B’,'I’);Fault from server: Service is not deployed.Cause: This error is thrown by server when invoked service is generated but not deployed.Resolution: Deploy this service from Integration Repository UI.Fault from server: Error occured while service was processing.Cause: This error is thrown by server when a internal error happens in Service Provider.Resolution: View SOAP Response via SOA Monitor UI. It has a error trace of the error happened in server. This should give a fair idea of what went wrong.

   第二种实现方式:通过JaxWsProxyFactoryBean代理类来设定服务处理类和服务地址,无须额外的客户端配置。

    @Test    public  void text3() {        // 以下和服务端配置类似,不对,应该说服务端和这里的安全验证配置一致        Map<String, Object> map = new HashMap<String, Object>();        map.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);        map.put(WSHandlerConstants.USER, "admin");        map.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);        // 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器        map.put(WSHandlerConstants.PW_CALLBACK_CLASS, DemoClientPasswordCallback.class.getName());        ArrayList list = new ArrayList();        // 添加cxf安全验证拦截器,必须        list.add(new SAAJOutInterceptor());        list.add(new WSS4JOutInterceptor(map));        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();        // WebServiceSample服务端接口实现类        factory.setServiceClass(CxfDemo.class);        // 设置ws访问地址        factory.setAddress("http://localhost:8080/shzj/webservice/helloWorld?wsdl");        //注入拦截器,用于加密安全验证信息        factory.getOutInterceptors().addAll(list);        CxfDemo service = (CxfDemo) factory.create();        String response = service.helloWord("小米");        System.out.println("返回: " + response);    }


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表