【问题标题】:Java Web Service client basic authenticationJava Web Service 客户端基本身份验证
【发布时间】:2011-10-27 15:12:54
【问题描述】:

我在 Glassfish 之上创建了一个 JAX-WS Web 服务,它需要基本的 HTTP 身份验证。

现在我想为该 Web 服务创建一个独立的 Java 应用程序客户端,但我不知道如何传递用户名和密码。

它与 Eclipse 的 Web 服务资源管理器一起工作,并检查了我发现的线路:

POST /SnaProvisioning/SnaProvisioningV1_0 HTTP/1.1
Host: localhost:8080
Content-Type: text/xml; charset=utf-8
Content-Length: 311
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: IBM Web Services Explorer
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Authorization: Basic Z2VybWFuOmdlcm1hbg==
Connection: close

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ngin.ericsson.com/sna/types/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <q0:listServiceScripts/>
  </soapenv:Body>
</soapenv:Envelope>

如何使用 java 代码在此“授权”标头中传递用户名和密码?它是散列还是类似的东西?算法是什么?

在不涉及安全性的情况下,我有一个独立的 Java 客户端:

SnaProvisioning myPort = new SnaProvisioning_Service().getSnaProvisioningV10Port();
myPort.listServiceScripts();

【问题讨论】:

    标签: java web-services jakarta-ee jax-ws


    【解决方案1】:

    基本认证的JAX-WS方式是

    Service s = new Service();
    Port port = s.getPort();
    
    BindingProvider prov = (BindingProvider)port;
    prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
    prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
    
    port.call();
    

    【讨论】:

    • 也感谢我!我会花 很长 时间来解决这个问题。
    • 对于1.5级的,需要为BindingProvider添加这个依赖: javax.xmlwebservices-api1.5
    • 很好的答案。非常感谢。
    【解决方案2】:

    事实证明,有一种简单、标准的方法可以实现我想要的:

    import java.net.Authenticator;
    import java.net.PasswordAuthentication;
    
    Authenticator myAuth = new Authenticator() 
    {
        @Override
        protected PasswordAuthentication getPasswordAuthentication()
        {
            return new PasswordAuthentication("german", "german".toCharArray());
        }
    };
    
    Authenticator.setDefault(myAuth);
    

    没有自定义“sun”类或外部依赖项,也没有手动编码任何东西。

    我知道 BASIC 安全性并不安全,但我们也在使用 HTTPS。

    【讨论】:

    • 请注意Authenticator#setDefault 不是线程安全的,如果您的服务使用者访问多个端点,这不是一个好的解决方案。
    • 是否有任何允许多个端点的线程安全替代方案?
    • Authenticator 可用于任何类型的安全协议,但提供凭据的 JAX-WS 方式不需要此方法。
    • 不幸的是,如果您的用户名是 unicode 而不是来自 Latin1 的用户名,则此解决方案将不起作用 :(
    • 如果您以后想以编程方式更改凭据,您可能会遇到与this 错误/缺陷相关的this 问题。如果仅使用基本身份验证保护服务端口,最简单的解决方案是(再次)乔纳森的答案。如果 WSDL 本身受到保护,则只有其他线程中描述的丑陋解决方法。
    【解决方案3】:

    对于Axis2 客户,这可能会有所帮助

    ...
    serviceStub = new TestBeanServiceStub("<WEB SERVICE URL>"); // Set your value
    HttpTransportProperties.Authenticator basicAuthenticator = new HttpTransportProperties.Authenticator();
    List<String> authSchemes = new ArrayList<String>();
    authSchemes.add(Authenticator.BASIC);
    basicAuthenticator.setAuthSchemes(authSchemes); 
    basicAuthenticator.setUsername("<UserName>"); // Set your value
    basicAuthenticator.setPassword("<Password>"); // Set your value
    basicAuthenticator.setPreemptiveAuthentication(true);
    serviceStub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, basicAuthenticator);
    serviceStub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, "false");
    ...
    

    【讨论】:

    • 我不得不更改 authSchemes.add(Authenticator.BASIC);到 authSchemes.add(HttpTransportProperties.Authenticator.BASIC);让它编译。
    • 嗨 Avil,我的 Axis2 客户端中没有存根类。对不起,我是初学者。我正在使用商业供应商的服务,客户由供应商提供。我做了wsimport,但没有存根类。所以我不能_getServiceClient().getOptions() 做这部分。执行wsimport 时是否需要添加任何其他属性?请帮我。感谢您的帮助。
    【解决方案4】:

    一些关于基本身份验证的附加上下文,它包含在包含键/值对的标头中:

    授权:基本 Z2VybWFuOmdlcm1hbg==

    其中“Authorization”是标题键, 并且标头值有一个字符串(“Basic”字加上空格)连接到“ Z2VybWFuOmdlcm1hbg==",用户名和密码,base 64双点连接

    String name = "username";
    String password = "secret";
    String authString = name + ":" + password;
    String authStringEnc = new BASE64Encoder().encode(authString.getBytes());
    ...
    objectXXX.header("Authorization", "Basic " + authStringEnc);
    

    【讨论】:

      【解决方案5】:

      如果您为客户端使用 JAX-WS 实现,例如 Metro Web 服务,以下代码显示如何在 HTTP 标头中传递用户名和密码:

       MyService port = new MyService();
       MyServiceWS service = port.getMyServicePort();
      
       Map<String, List<String>> credentials = new HashMap<String,List<String>>();
      
       credentials.put("username", Collections.singletonList("username"));
       credentials.put("password", Collections.singletonList("password"));
      
       ((BindingProvider)service).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, credentials);
      

      然后对服务的后续调用将被验证。请注意,密码仅使用 Base64 编码,因此我鼓励您使用其他附加机制(如客户端证书)来提高安全性。

      【讨论】:

      • 这对于手动添加任意标头和设置任意值很有用(通过手动计算凭据的 base64 编码),但还有更多标准选项
      【解决方案6】:

      这对我有用:

       BindingProvider bp = (BindingProvider) port;
       Map<String, Object> map = bp.getRequestContext();
       map.put(BindingProvider.USERNAME_PROPERTY, "aspbbo");
       map.put(BindingProvider.PASSWORD_PROPERTY, "9FFFN6P");
      

      【讨论】:

      • 请使用英文
      【解决方案7】:

      为了让您的生活更简单,您可能需要考虑使用 JAX-WS 框架,例如 Apache CXF 或 Apache Axis2。

      这里是描述如何为 Apache CXF 设置 WS-Security 的链接 -> http://cxf.apache.org/docs/ws-security.html

      编辑 顺便说一句,Authorization 字段只是使用简单的 Base64 编码。 据此(http://www.motobit.com/util/base64-decoder-encoder.asp),解码后的值为german:german

      【讨论】:

      • Web 服务已经工作了很长一段时间,增加安全性只是向单个类添加单个注释 (@RolesAllowed) 的问题,我认为没有比这更简单的了尤其是当我查看 CXF 所需的大量配置时。除此之外,仅仅因为客户端无法发送(还)一个标头而改变框架是不值得的。
      • @German.从您的问题中不清楚您在客户端中使用的是 any 框架。看起来你自己的答案是赢家。
      • 是的,也许不清楚我使用的框架,问题是我们没有任何 jar 或依赖项或任何引用特定实现的东西,但我想如果我们正在使用Glassfish,那么我们正在使用 Metro。
      【解决方案8】:

      如果您使用 JAX-WS,以下对我有用:

          //Get Web service Port
          WSTestService wsService = new WSTestService();
          WSTest wsPort = wsService.getWSTestPort();
      
          // Add username and password for Basic Authentication
          Map<String, Object> reqContext = ((BindingProvider) 
               wsPort).getRequestContext();
          reqContext.put(BindingProvider.USERNAME_PROPERTY, "username");
              reqContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
      

      【讨论】:

        【解决方案9】:

        最简单的方法是在请求下包含用户名和密码。请参阅下面的示例。

        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:typ="http://xml.demo.com/types" xmlns:ser="http://xml.demo.com/location/services"
            xmlns:typ1="http://xml.demo.com/location/types">
            <soapenv:Header>
                <typ:requestHeader>
                    <typ:timestamp>?</typ:timestamp>
                    <typ:sourceSystemId>TEST</typ:sourceSystemId>
                    <!--Optional: -->
                    <typ:sourceSystemUserId>1</typ:sourceSystemUserId>
                    <typ:sourceServerId>1</typ:sourceServerId>
                    <typ:trackingId>HYD-12345</typ:trackingId>
                </typ:requestHeader>
        
                <wsse:Security soapenv:mustUnderstand="1"
                    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                    <wsse:UsernameToken wsu:Id="UsernameToken-emmprepaid"
                        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                        <wsse:Username>your-username</wsse:Username>
                        <wsse:Password
                            Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">your-password</wsse:Password>
                    </wsse:UsernameToken>
                </wsse:Security>
            </soapenv:Header>
            <soapenv:Body>
                <ser:getLocation>
                    <!--Optional: -->
                    <ser:GetLocation>
                        <typ1:locationID>HYD-GoldenTulipsEstates</typ1:locationID>
                    </ser:GetLocation>
                </ser:getLocation>
            </soapenv:Body>
        </soapenv:Envelope>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-01
          • 1970-01-01
          • 2012-01-03
          • 2018-07-03
          相关资源
          最近更新 更多