Java Web Service 客户端基本身份验证
Posted
技术标签:
【中文标题】Java Web Service 客户端基本身份验证【英文标题】:Java Web Service client basic authentication 【发布时间】: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();
【问题讨论】:
【参考方案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
添加这个依赖: 事实证明,有一种简单、标准的方法可以实现我想要的:
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>
【讨论】:
以上是关于Java Web Service 客户端基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章
web service001——web service简单认识
Java Restful Web Services (jax rs) 身份验证模式