Axis2生成了客户端代码,但是服务端要求用户名、密码验证,不知道客户端如何加入。
客户端的CallbackHandler类如下,但是不知道如何加入soap的head中,在CXF中可以容易的处理,但是Axis2就不知道怎么处理了。请各位施以援手。
package axis.ws.testing;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 {
private String userid;
private String password;

public String getUserid() {
return userid;
} public void setUserid(String userid) {
this.userid = userid;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// ApplicationContext context= SpringUtil.getContext();
// PluginConfig cfg = (PluginConfig) context.getBean("globalCfg");
pc.setIdentifier(this.getUserid());
pc.setPassword(this.getPassword());
}
}

解决方案 »

  1.   

    在客户端需要使用setManageSession(true)打开Session 管理功能。     实现同一个WebService 的Session 管理需要如下三步:     1. 使用MessageContext 和ServiceContext 获得与设置key-value 对。     2. 为要进行Session 管理的WebService 类所对应的<service>元素添加一个scope 属性,并将该属性值设为 transportsession。     3. 在客户端使用setManageSession(true)打开Session 管理功能。     下面是一个在同一个WebService 类中管理Session 的例子。 
    package service; 
    import org.apache.axis2.context.ServiceContext; 
    import org.apache.axis2.context.MessageContext; 
    public class LoginService 
    {    public boolean login(String username, String password) 
       { 
          if("bill".equals(username) && "1234".equals(password)) 
          {
            // 第1步:设置key-value 对 
             MessageContext mc = MessageContext.getCurrentMessageContext(); 
            ServiceContext sc = mc.getServiceContext(); 
            sc.setProperty("login", "成功登录"); 
            return true; 
          } 
          else 
          { 
            return false; 
          } 
       }    public String getLoginMsg() 
       { 
         //  第1步:获得key-value 对中的value 
          MessageContext mc = MessageContext.getCurrentMessageContext(); 
          ServiceContext sc = mc.getServiceContext(); 
          return (String)sc.getProperty("login"); 
       } 

      

  2.   

    谢谢楼上的兄弟,貌似贴的server端代码。 我的server短已经实现了,用CXF做的。现在由于要兼容jdk1.4,我不得不放弃用cxf做客户端,选用了asis2.
    能否贴点客户端的代码上来?
      

  3.   

    使用如下的命令生成客户端使用的stub 类: %AXIS2_HOME%\bin\wsdl2java -uri http://localhost:8080/axis2/services/loginService?wsdl -p client -s -o stub 在stub\src\client 目录中生成了一个LoginServiceStub.java 类,在该类中找到如下的构造句法: public LoginServiceStub(org.apache.axis2.context.ConfigurationContext configurationContext, String targetEndpoint, boolean useSeparateListener)  throws org.apache.axis2.AxisFault 
    {    _serviceClient.getOptions().setSoapVersionURI( org.apache.axiom.soap.SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI); } 在该方法中最后添加如下的代码: 
    // 第3 步:打开客户端的Session 管理功能 
    _serviceClient.getOptions().setManageSession(true); 
        下面的客户端代码使用LoginServiceStub 对象访问了刚才建立的WebService: LoginServiceStub stub = new LoginServiceStub(); 
    LoginServiceStub.Login login = new LoginServiceStub.Login(); 
    login.setUsername("bill"); 
    login.setPassword("1234"); 
    if(stub.login(login).local_return) {    System.out.println(stub.getLoginMsg().local_return); }     运行上面的代码后,会输出“成功登录”信息
      

  4.   

    谢谢 gl74gs48, 您是把login当成一个普通的webserver的方法访问。但是如果有其他方法,貌似可以直接访问,哪怕不输入用户名、密码。 不知道我理解的对不对。server端用到了ws:security的简单用户验证,既强制要求所有的webservice访问必须加入授权信息。
      

  5.   

    看到你的评论了,问题应该已经解决了吧。
    在axis2中加入soap的登录信息到header,代码示例如下:
    String username = "admin";//服务器端分配的用户名
            String password = "1";//服务器端分配的密码
            ServiceClient client = stub._getServiceClient();
            SOAP11Factory factory = new SOAP11Factory();        OMNamespace SecurityElementNamespace = factory
                    .createOMNamespace(
                            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                            "wsse");        OMElement usernameTokenEl = factory.createOMElement("UsernameToken",
                    SecurityElementNamespace);
            OMElement usernameEl = factory.createOMElement("Username",
                    SecurityElementNamespace);
            OMElement passwordEl = factory.createOMElement("Password",
                    SecurityElementNamespace);
            OMElement actionEl = factory.createOMElement("Action",
                    SecurityElementNamespace);        passwordEl
                    .addAttribute(factory
                            .createOMAttribute(
                                    "Type",
                                    null,
                                    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"));        usernameEl.setText(username);
            passwordEl.setText(password);
            usernameTokenEl.addChild(usernameEl);
            usernameTokenEl.addChild(passwordEl);
            usernameTokenEl.addChild(actionEl);
            SOAPHeaderBlockImpl block = new SOAP11HeaderBlockImpl("Security",
                    SecurityElementNamespace, factory);
            block.addChild(usernameTokenEl);        client.addHeader(block);
      

  6.   

    怎么实现的验证,我调用sharepoint的webservices 总是提示我没有权限。想参考一下你解决的方法,能提供吗,谢谢
      

  7.   

    想问一下,服务端的PasswordType是PasswordDigest,我把"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"中的PasswordText直接改为PasswordDigest是会报错的:
     An invalid security token was provided (An error happened processing a Username Token "{0}")
    这要怎么解决啊?
      

  8.   

    想问一下,服务端的PasswordType是PasswordDigest,我把"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"中的PasswordText直接改为PasswordDigest是会报错的:
     An invalid security token was provided (An error happened processing a Username Token "{0}")
    这要怎么解决啊?
      

  9.   

    楼主,可否将你的代码共享一下,主要是你的service里面要怎么去写,急需要
      

  10.   

    楼主说的CXF怎么实现验证,求解啊
      

  11.   

    LZ可以说说CXF怎么处理这个问题吗?
      

  12.   

    回w2221121, 对不起,没有及时回复,现在上csdn少了,1. 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:jaxws="http://cxf.apache.org/jaxws"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd"> <bean id="clientReport" class="code.review.ws.ReportCreator"
    factory-bean="clientFactory1" factory-method="create" /> <bean id="clientFactory1" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"
    p:address="http://192.168.0.23:17081/CodeReviewWs/ReportCreator">
    <property name="serviceClass" value="code.review.ws.ReportCreator" />
    <property name="outInterceptors">
    <list>
    <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
    <ref bean="wsOutInterceptor" />
    </list>
    </property>
    </bean>
    <bean id="clientPasswordCallback" class="code.review.security.ClientPasswordCallback" >
    <property name="userid" value="web_admin" />
    <property name="password" value="123456" />
    </bean>
    <bean id="wsOutInterceptor" 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="admin" />
    <entry key="passwordCallbackRef">
    <ref bean="clientPasswordCallback" />
    </entry>
    </map>
    </constructor-arg>
    </bean>
    </beans>
    主要是clientPasswordCallback,这个就是验证密码用的,因为我的引用用户名/密码是固定的,所以写死了。2. clientPasswordCallback代码如下,package code.review.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;
    /**
     * @author Stony Zhang  
     * @Createdate 2010-8-5 
     */
    public class ClientPasswordCallback implements CallbackHandler {
    private String userid;
    private String password;

    public String getUserid() {
    return userid;
    } public void setUserid(String userid) {
    this.userid = userid;
    } public String getPassword() {
    return password;
    } public void setPassword(String password) {
    this.password = password;
    } public void handle(Callback[] callbacks) throws IOException,
    UnsupportedCallbackException {
    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    // ApplicationContext context = SpringUtil.getContext();
    // PluginConfig cfg = (PluginConfig) context.getBean("globalCfg");
    pc.setIdentifier(getUserid());
    pc.setPassword(getPassword());
    }
    }
    看handle方法即可, 你可能根据你的需要,做些修改。
      

  13.   

    回 ShuangZuoxing, Client部分请看以上回复,Server端部分如下,Spring配置, <bean id="WSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordText" />
                    <!--
    <entry key="passwordCallbackClass" value="code.review.security.PasswordCallback" />
      passwordCallbackClass is the same with  passwordCallbackRef. one is class name, another is bean managed-->
    <entry key="passwordCallbackRef">
                        <ref bean="serverPasswordCallback"/>
                    </entry>      </map> </constructor-arg>
    </bean> <bean id="serverPasswordCallback" class="code.review.security.PasswordCallback"> </bean>package code.review.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;
    import org.apache.ws.security.WSSecurityException;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;import code.review.entity.User;
    import code.review.ws.dao.UserDao;
    /**
     * @author Stony Zhang  
     * @Createdate 2010-8-5 
     */
    public class PasswordCallback implements CallbackHandler,ApplicationContextAware {
    private ApplicationContext context; @Override
    public void setApplicationContext(ApplicationContext arg0)
    throws BeansException {
    this.context = arg0;
    } @Override
    public void handle(Callback[] callbacks) throws IOException,
    UnsupportedCallbackException {
    for (int i = 0; i < callbacks.length; i++) {
    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
    // if (!passwords.containsKey(pc.getIdentifier())) {
    // throw new WSSecurityException("user not match");
    // }
    String userId=pc.getIdentifier();
    // String pass = passwords.get(pc.getIdentifier());
    String pwd = pc.getPassword();

     
    UserDao userDao = (UserDao) context.getBean("userDao");
    User user=userDao.findByUserId(userId);
    // System.out.println("userid=" + userId + " password=" + pwd);
    boolean isMatch=user!=null && user.getPassword().equals(pwd);
    if (!isMatch) {
    throw new WSSecurityException("your userId or password not match");
    }
    this.passwords.put(userId, pwd);
    } }
    }
      

  14.   

    请问w2221121,你的axis2授权解决了吗,能不能给些指点,谢谢。