JAX-WS和基本身份验证,当用户名和密码存储在数据库中

24

我对JAX-WS不熟悉,有一件事我不理解。

有很多教程可以用来设置JAX-WS安全性,但在几乎所有情况下,BindingProvider.USERNAME_PROPERTY和BindingProvider.PASSWORD_PROPERTY都存储在某个.xml文件中(取决于容器),它们是“硬编码”的。这就是我不明白的地方。如何通过将BindingProvider.USERNAME_PROPERTY和BindingProvider.PASSWORD_PROPERTY与数据库中的用户名和密码进行比较来验证Web服务客户端?我尝试在客户端上像这样设置BindingProvider.USERNAME_PROPERTY和BindingProvider.PASSWORD_PROPERTY:

    ShopingCartService scs = new ShopingCartService(wsdlURL, name);
    ShopingCart sc = scs.getShopingCartPort();
    Map<String, Object> requestContext = ((BindingProvider)sc).getRequestContext();
    requestContext.put(BindingProvider.USERNAME_PROPERTY, userName);
    requestContext.put(BindingProvider.PASSWORD_PROPERTY, password);
    sc.someFunctionCall();

然后,在服务器端像这样检索:

@Resource
WebServiceContext wsContext;

@WebMethod
public void someFunctionCall() {
    MessageContext mc = wsContext.getMessageContext();
    mc.get(BindingProvider.USERNAME_PROPERTY);
    mc.get(BindingProvider.PASSWORD_PROPERTY);
}

但是我总是得到null,我在xml中没有设置任何东西,web服务工作得非常好,只是我无法获取那些变量 :(

我正在运行java 1.6、tomcat 6和JAX-WS

非常感谢任何有关使用数据库中的密码对用户进行身份验证的帮助, 谢谢。


我也尝试在SOAPHandler中检查BindingProvider.USERNAME_PROPERTY,但仍然为null。 - ahoge
7个回答

20
我认为您正在寻找应用程序级别的JAX-WS身份验证,而不是服务器级别的HTTP基本身份验证。请参阅以下完整示例: JAX-WS应用程序身份验证 在Web服务客户端上,只需将您的“用户名”和“密码”放入请求头即可。
Map<String, Object> req_ctx = ((BindingProvider)port).getRequestContext();
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WS_URL);

Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Username", Collections.singletonList("someUser"));
headers.put("Password", Collections.singletonList("somePass"));
req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);

在 Web 服务服务器端,通过 WebServiceContext 获取请求头参数。

@Resource
WebServiceContext wsctx;

@WebMethod
public String method() {
    MessageContext mctx = wsctx.getMessageContext();

    Map http_headers = (Map) mctx.get(MessageContext.HTTP_REQUEST_HEADERS);
    List userList = (List) http_headers.get("Username");
    List passList = (List) http_headers.get("Password");
    //...

1
我能问一下您从哪里得到这样的信息吗?我需要官方的信息来源,但是我找不到足够的官方来源! - Muhammad Gelbana

12

BindingProvider.USERNAME_PROPERTY 和 BindingProvider.PASSWORD_PROPERTY 是匹配的 HTTP 基本身份验证机制,可以在 HTTP 级别而非应用程序或 Servlet 级别启用身份验证过程。

基本上,只有 HTTP 服务器会知道用户名和密码(根据 HTTP/应用服务器规范可能还涉及应用程序,例如 Apache/PHP)。 对于 Tomcat/Java,可以在 web.xml 中添加登录配置 BASIC,以及适当的 security-constraint/security-roles(将稍后与真实用户的用户/组相关联的角色)。

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>YourRealm</realm-name>
</login-config>

然后,在HTTP服务器(或应用服务器)层面上将领域与适当的用户存储库连接起来。对于Tomcat,您可以查看JAASRealm、JDBCRealm或DataSourceRealm,这些可能适合您的需求。

http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html


6

感谢(最好将解决方案复制/粘贴到这里... :P) - boly38

1
在您的客户端SOAP处理程序中,您需要设置javax.xml.ws.security.auth.username和javax.xml.ws.security.auth.password属性如下:
public class ClientHandler implements SOAPHandler<SOAPMessageContext>{

    public boolean handleMessage(final SOAPMessageContext soapMessageContext)
    {
        final Boolean outInd = (Boolean)soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outInd.booleanValue())
        {
          try 
          {
               soapMessageContext.put("javax.xml.ws.security.auth.username", <ClientUserName>);
               soapMessageContext.put("javax.xml.ws.security.auth.password", <ClientPassword>);
          } 
          catch (Exception e)
          {
               e.printStackTrace();
               return false;
          }
         }
      return true;
     }
}

1

关于同时使用应用程序级别的身份验证和HTTP基本身份验证的示例,请参阅我的以前的帖子之一。


1

我曾经遇到过类似的情况,需要向我的WS提供用户名、密码和WSS密码类型。

最初我使用了“Http基本认证”(如@ahoge所述),我也尝试使用@Philipp-Dev的参考资料。但是我没有得到成功的解决方案。

在谷歌上进行了一番深入搜索后,我找到了这篇文章:

https://dev59.com/XXA75IYBdhLWcg3wy8fr#3117841

这就是我的问题解决方案

我希望这个能帮到其他人,像它帮助了我一样。

敬礼, iVieL


0
如果您以这种方式将客户端的用户名和密码放入请求中:
URL url = new URL("http://localhost:8080/myapplication?wsdl");
MyWebService webservice = new MyWebServiceImplService(url).getMyWebServiceImplPort();
Map<String, Object> requestContext = ((BindingProvider) webservice).getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "myusername");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "mypassword");

并调用您的 Web 服务

String response = webservice.someMethodAtMyWebservice("test");

然后你可以在服务器端这样读取基本身份验证字符串(你需要添加一些检查和异常处理):
@Resource
WebServiceContext webserviceContext;

public void someMethodAtMyWebservice(String parameter) {
    MessageContext messageContext = webserviceContext.getMessageContext();
    Map<String, ?> httpRequestHeaders = (Map<String, ?>) messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
    List<?> authorizationList = (List<?>) httpRequestHeaders.get("Authorization");
    if (authorizationList != null && !authorizationList.isEmpty()) {
        String basicString = (String) authorizationList.get(0);
        String encodedBasicString = basicString.substring("Basic ".length());
        String decoded = new String(Base64.getDecoder().decode(encodedBasicString), StandardCharsets.UTF_8);
        String[] splitter = decoded.split(":");
        String usernameFromBasicAuth = splitter[0];
        String passwordFromBasicAuth = splitter[1];
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接