android消费的navision Web服务

时间:2013-02-25 16:01:39

标签: android service web navision dynamics-nav

我需要从android使用NAV Web服务。 我得到了“Letters”codeunit和“Upper”函数。

我已经在我的PC上设置了NAV Web服务(NTLM身份验证)并关闭了防火墙(以便在我的网络中的其他设备上显示此服务)。输入登录/通过(我的PC帐户)后,可以在浏览器(也在adroid设备上)访问该服务。 如果我使用this code,它会在END_DOCUMENT null异常的“调用”中崩溃... 那是因为认证吗?

如果我使用此代码连接

HttpGet request = new
HttpGet("http://[myPC'sIP]:7047/DynamicsNAV/WS/SystemService");
HttpResponse response = client.execute(request);

我收到401错误,但只是指定了IP

HttpGet request = new HttpGet("http://[myPC'sIP]");
HttpResponse response = client.execute(request);

返回代码200(ok) 我该如何发送凭证?我试过几种方法,但结果总是一样的...... 你有这个问题的经验吗?

5 个答案:

答案 0 :(得分:1)

我使用soap_action做同样的事情并且它像魅力一样工作,看看下面的代码是否有助于你:

String namespace = "urn:microsoft-dynamics-schemas/codeunit/NavisionWS";
String url = "http://IP:7047/DynamicsNAV/WS/Codeunit/NavisionWS";   
String soap_action = "urn:microsoft-dynamics-schemas/codeunit/NavisionWS:GetLoginInfo";
String method_name = "GetLoginInfo";
try
        {
              SoapObject request = new SoapObject(namespace, method_name);    
              SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

               envelope.dotNet = true;   
               envelope.setOutputSoapObject(request);   
               HttpTransportSE transport = new HttpTransportSE(url);    
               transport.call(soap_action, envelope); // Receive Error here!
                    SoapObject result = (SoapObject) envelope.getResponse();
                    great = result.toString();
        }
        catch (Exception e)
        {
            e.printStackTrace();
                 great = e.toString();
                 Toast.makeText(this, great, Toast.LENGTH_LONG).show();
        }

答案 1 :(得分:1)

1)在坛子下面添加 的 JCIFS-1.3.17.jar ksoap2-机器人组装-3.0.0-罐与 - dependencies.jar

2)创建这些java类 的 JCIFSEngine.java

package com.demo.Authentication;
import jcifs.ntlmssp.NtlmFlags;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.util.Base64;
import org.apache.http.impl.auth.NTLMEngine;
import org.apache.http.impl.auth.NTLMEngineException;

import java.io.IOException;

/**
 * Class taken from http://hc.apache.org/httpcomponents-client-ga/ntlm.html
 */
public final class JCIFSEngine implements NTLMEngine {

    private static final int TYPE_1_FLAGS =
            NtlmFlags.NTLMSSP_NEGOTIATE_56 |
            NtlmFlags.NTLMSSP_NEGOTIATE_128 |
            NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
            NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
            NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return Base64.encode(type1Message.toByteArray());
    }

    public String generateType3Msg(final String username, final String password,
            final String domain, final String workstation, final String challenge)
            throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, password, domain,
                username, workstation, type3Flags);
        return Base64.encode(type3Message.toByteArray());
    }
}

<强> NtlmTransport.java

package com.demo.Authentication;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.ksoap2.HeaderProperty;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.ServiceConnection;
import org.ksoap2.transport.Transport;
import org.xmlpull.v1.XmlPullParserException;


public class NtlmTransport extends Transport {

    static final String ENCODING = "utf-8";

    private final DefaultHttpClient client = new DefaultHttpClient();
    private final HttpContext localContext = new BasicHttpContext();
    private String urlString;
    private String user;
    private String password;
    private String ntDomain;
    private String ntWorkstation;
    public static String AuthenticationCode;

    public NtlmTransport(String url, String user, String password,
            String domain, String workStation) {
this.urlString = url;
this.user = user;
this.password = password;
this.ntDomain = domain;
this.ntWorkstation = workStation;

}

    public void setCredentials(String url, String user, String password,
                               String domain, String workStation) {
        this.urlString = url;
        this.user = user;
        this.password = password;
        this.ntDomain = domain;
        this.ntWorkstation = workStation;

    }

    public List call(String targetNamespace, SoapEnvelope envelope, List headers)
            throws IOException, XmlPullParserException {
        return call(targetNamespace, envelope, headers, null);
    }

    public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile)
            throws IOException, XmlPullParserException {
        if (outputFile != null) {
            // implemented in HttpTransportSE if you are willing to port..
            throw new RuntimeException("Writing to file not supported");
        }
        HttpResponse resp = null;

        setupNtlm(urlString, user, password);

        try {
            // URL url = new URL(urlString);
            HttpPost httppost = new HttpPost(urlString);

            setHeaders(soapAction, envelope, httppost, headers);

            resp = client.execute(httppost, localContext);
            HttpEntity respEntity = resp.getEntity();


            InputStream is = respEntity.getContent();
            parseResponse(envelope, is);

        } catch (Exception ex) {
             ex.printStackTrace();
        }

        System.out.println("RESPONSE STATUS CODE :"+resp.getStatusLine().getStatusCode());
        if (resp != null) {
            return Arrays.asList(resp.getAllHeaders());
        } else {
            return null;
        }
    }

    private void setHeaders(String soapAction, SoapEnvelope envelope, HttpPost httppost, List headers) {
        byte[] requestData = null;
        try {
            requestData = createRequestData(envelope);
        } catch (IOException iOException) {
        }
        ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData);
        httppost.setEntity(byteArrayEntity);
        httppost.addHeader("User-Agent", org.ksoap2.transport.Transport.USER_AGENT);
        // SOAPAction is not a valid header for VER12 so do not add
        // it
        // @see "http://code.google.com/p/ksoap2-android/issues/detail?id=67
        if (envelope.version != SoapSerializationEnvelope.VER12) {
            httppost.addHeader("SOAPAction", soapAction);
        }

        if (envelope.version == SoapSerializationEnvelope.VER12) {
            httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8);
        } else {
            httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_XML_CHARSET_UTF_8);
        }

        // Pass the headers provided by the user along with the call
        if (headers != null) {
            for (int i = 0; i < headers.size(); i++) {
                HeaderProperty hp = (HeaderProperty) headers.get(i);
                httppost.addHeader(hp.getKey(), hp.getValue());
            }
        }
    }


    // Try to execute a cheap method first. This will trigger NTLM authentication
    public void setupNtlm(String dummyUrl, String userId, String password) {
        try {

            ((AbstractHttpClient) client).getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

            NTCredentials creds = new NTCredentials(userId, password, ntWorkstation, ntDomain);
            client.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);

            HttpGet httpget = new HttpGet(dummyUrl);

            HttpResponse response1 = client.execute(httpget, localContext);
            HttpEntity entity1 = response1.getEntity();
            Header[] hArray = response1.getAllHeaders();
            int size = hArray.length;
            AuthenticationCode = String.valueOf(response1.getStatusLine().getStatusCode());
            System.out.println("AUTHENTICATION STATUS CODE :"+response1.getStatusLine().getStatusCode());
           /* for (int i = 0; i < size; i ++) {
                Header h = hArray[i];
                if (h.getName().equals("WWW-Authenticate")) {
                    entity1.consumeContent();
                    throw new Exception("Failed Authentication");
                }
            }*/

            entity1.consumeContent();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

        //NTLM Scheme factory
    private class NTLMSchemeFactory implements AuthSchemeFactory {
        public AuthScheme newInstance(final HttpParams params) {
        // see http://www.robertkuzma.com/2011/07/
        // manipulating-sharepoint-list-items-with-android-java-and-ntlm-authentication/
            return new NTLMScheme(new JCIFSEngine());
        }
    }

    public ServiceConnection getServiceConnection() throws IOException
    {
        throw new IOException("Not using ServiceConnection in transport");
    }

    public String getHost() {
        String retVal = null;
        try {
            retVal = new URL(url).getHost();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }

    public int getPort() {
        int retVal = -1;
        try {
            retVal = new URL(url).getPort();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }

    public String getPath() {
        String retVal = null;
        try {
            retVal = new URL(url).getPath();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }
}

3) 使用paramater url,“username”,“password”,“domainName”,“SystemName”调用此方法

 NtlmTransport ntlm = new NtlmTransport(url, "username", "password", "domainName","SystemName");

4)发送包含Soap Envelope的Soap Request。

 ntlm.call("namespace/methodname", soapEnvelope);

答案 2 :(得分:0)

通过创建另一个Web服务(在C#上编写,在运行NAV服务器的同一台PC上运行)来解决,该服务读取NAV服务并通过此C#WS与NAV WS进行通信

答案 3 :(得分:0)

你好,你试过用

var httpClient = new DefaultHttpClient();
NTCredentials nt = new NTCredentials("user", "pass", "", "domain");
httpClient.GetCredentialsProvider().SetCredentials(AuthScope.ANY, nt);

答案 4 :(得分:0)

这是http身份验证supposed to work的方式。您可以使用fiddler查看您的中介正在做什么。如果你想摆脱它,你将不得不做同样的事情:)

据说使用Navision认证不是野餐,因为它使用SPNEGO或NTLM。如果您可以配置NTLM,则可以使用android-ntlm来完成工作。看起来类似于pungggi的答案,httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

除外