2011-03-02 151 views
3

要验证的请求,我用Authenticator.setDefault 这是VM宽...
如果我想单独不同的web服务 并且每一个都知道自己的身份验证凭据。
对于每个请求,我是否需要Authenticator.setDefault
如果存在并发连接的混合Web服务,这可能不起作用...如何处理多个身份验证

回答

-1

缺少答案往往意味着没有人知道,这告诉我没有答案。

我一直在想同样的事情,我想答案是它不能通过java.net来完成。我认为你需要一次限制你的http访问到一台服务器,或者查看其他包,比如org.apache.http.client。

0

这是我实施的解决方案,它的作用就像一个魅力!

import java.net.*; 
import java.util.*; 
import java.util.logging.*; 
import java.util.regex.*; 

/** 
* Authenticator which keeps credentials to be passed to the requester 
* based on the concatenation of the authority and the URL that requires 
* authentication. 
* 
* If the configured credentials are not found, the Authenticator will 
* use the embedded credentials if present. 
* 
* Embedded credentials are in the form of <pre><b>user</b>:<b>password</b><i>@host:port/&lt;url-path&gt;</i></pre> 
* 
* @author Michael Fortin 2011-09-23 
*/ 
public class Authenticator extends java.net.Authenticator { 

    private Logger log = Logger.getLogger(this.getClass().getName()); 
    private Map<String, PasswordAuthentication> authInfos; 
    private Pattern embeddedAuthInfoPattern; 

    @Override 
    protected PasswordAuthentication getPasswordAuthentication() { 

     String requesterInfo = String.format("%s%s", getRequestingURL().getAuthority(), getRequestingURL().getPath()); 
     log.fine(String.format("%s at \"%s\" is requesting %s password authentication for \"%s\"", getRequestorType(), getRequestingPrompt(), getRequestingScheme(), requesterInfo)); 
     PasswordAuthentication pa = null; 

     if ((pa = authInfos.get(requesterInfo)) == null && (pa = getEmbeddedPA(getRequestingURL().getAuthority())) == null) { 
      log.warning(String.format("No authentication information for \"%s\"", requesterInfo)); 
     } 

     return pa; 
    } 

    public void setAuthInfos(Map<String, PasswordAuthentication> authInfos) { 
     this.authInfos = authInfos; 
    } 

    public void setEmbeddedAuthInfoPattern(String pattern) { 
     this.embeddedAuthInfoPattern = Pattern.compile(pattern); 
    } 

    private PasswordAuthentication getEmbeddedPA(String authInfo) { 
     if (authInfo != null) { 
      Matcher matcher = embeddedAuthInfoPattern.matcher(authInfo); 
      if (matcher.find()) { 
       return new PasswordAuthentication(matcher.group(1), matcher.group(2).toCharArray()); 
      } 
     } 
     return null; 
    } 
} 
2

迈克的反应大厦上面我有以下的解决方案,因为虽然我非常赞赏的总体思路(这就是为什么我把它抄了;-),我看到几个问题吧:

  • 如果JDK通过java.net.Authenticator中的两个不通过URL的静态请求方法之一请求身份验证,那么Mike的解决方案将抛出NullPointerException(然后getRequestingURL()将返回null)。
  • 它要求您传入解构URL的外部正则表达式模式。这非常容易出错,并且JDK中的URL类实现了此解析,所以我更愿意使用它。
  • 它需要某个外部类构建PasswordAuthentication对象的映射,然后进行设置。它没有实现系统中其他组件可以使用的注册机制。我也把它变成了一个单身人士。
  • 更多的风格:我不建议重复类名称(Authenticator),所以我将它重命名为DefaultAuthenticator。

下面的解决方案我认为解决了这些问题。

/** 
    * Authenticator which keeps credentials to be passed to the requestor based on authority of the requesting URL. The 
    * authority is <pre>user:[email protected]:port</pre>, where all parts are optional except the host. 
    * <p> 
    * If the configured credentials are not found, the Authenticator will use the credentials embedded in the URL, if 
    * present. Embedded credentials are in the form of <pre>user:[email protected]:port</pre> 
    * 
    * @author Michael Fortin 2011-09-23 
    */ 
    public final class DefaultAuthenticator extends Authenticator { 

     private static final Logger LOG = Logger.getLogger(DefaultAuthenticator.class.getName()); 
     private static DefaultAuthenticator instance; 

     private Map<String, PasswordAuthentication> authInfo = new HashMap<String, PasswordAuthentication>(); 

     private DefaultAuthenticator() { 
     } 

     public static synchronized DefaultAuthenticator getInstance() { 
      if (instance == null) { 
       instance = new DefaultAuthenticator(); 
       Authenticator.setDefault(instance); 
      } 
      return instance; 
     } 

     // unit testing 
     static void reset() { 
      instance = null; 
      Authenticator.setDefault(null);   
     } 

     @Override 
     protected PasswordAuthentication getPasswordAuthentication() { 

      String requestorInfo = getRequestorInfo(); 
      LOG.info(getRequestorType() + " at \"" + getRequestingPrompt() + "\" is requesting " + getRequestingScheme() 
        + " password authentication for \"" + requestorInfo + "\""); 

      if (authInfo.containsKey(requestorInfo)) { 
       return authInfo.get(requestorInfo); 
      } else { 
       PasswordAuthentication pa = getEmbeddedCredentials(getRequestingURL()); 
       if (pa == null) { 
        LOG.warning("No authentication information"); 
       } 
       return pa; 
      } 

     } 

     /** 
     * Register the authentication information for a given URL. 
     * 
     * @param url - the URL that will request authorization 
     * @param auth - the {@link PasswordAuthentication} for this URL providing the credentials 
     */ 
     public void register(URL url, PasswordAuthentication auth) { 
      String requestorInfo = getRequestorInfo(url.getHost(), url.getPort()); 
      authInfo.put(requestorInfo, auth); 
     } 

     /** 
     * Get the requestor info based on info provided. 
     * 
     * @param host - hostname of requestor 
     * @param port - TCP/IP port 
     * @return requestor info string 
     */ 
     private String getRequestorInfo(String host, int port) { 

      String fullHostname; 
      try { 
       InetAddress addr = InetAddress.getByName(host); 
       fullHostname = addr.getCanonicalHostName(); 
      } catch (UnknownHostException e) { 
       fullHostname = host; 
      } 

      if (port == -1) { 
       return fullHostname; 
      } else { 
       return fullHostname + ":" + port; 
      } 
     } 

     /** 
     * Get the requestor info for the request currently being processed by this Authenticator. 
     * 
     * @return requestor info string for current request 
     */ 
     private String getRequestorInfo() { 

      String host; 
      InetAddress addr = getRequestingSite(); 
      if (addr == null) { 
       host = getRequestingHost(); 
      } else { 
       host = addr.getCanonicalHostName(); 
      } 
      return getRequestorInfo(host, getRequestingPort()); 
     } 

     /** 
     * Get the credentials from the requesting URL. 
     * 
     * @param url - URL to get the credentials from (can be null, method will return null) 
     * @return PasswordAuthentication with credentials from URL or null if URL contains no credentials or if URL is 
     * null itself 
     */ 
     PasswordAuthentication getEmbeddedCredentials(URL url) { 

      if (url == null) { 
       return null; 
      } 

      String userInfo = url.getUserInfo(); 
      int colon = userInfo == null ? -1 : userInfo.indexOf(":"); 
      if (colon == -1) { 
       return null; 
      } else { 
       String userName = userInfo.substring(0, colon); 
       String pass = userInfo.substring(colon + 1); 
       return new PasswordAuthentication(userName, pass.toCharArray()); 
      } 
     } 
    } 

虽然我在这里,让我给你我的单元测试(JUnit 4)。

/** 
    * @author Paul Balm - May 10 2012 
    */ 
    public class DefaultAuthenticatorTest { 

     private static final Logger LOG = Logger.getLogger(DefaultAuthenticatorTest.class.getName()); 

     @Before 
     public void setUp() throws Exception { 
      DefaultAuthenticator.reset(); 
      DefaultAuthenticator.getInstance(); 
     } 

     @After 
     public void tearDown() { 
      DefaultAuthenticator.reset(); 
     } 

     @Test 
     public void testRequestAuthenticationFromURL() throws MalformedURLException, UnknownHostException { 

      Map<String, String[]> urls = generateURLs(); 

      for (String urlStr : urls.keySet()) { 
       String[] userInfo = urls.get(urlStr); 
       LOG.info("Testing: " + urlStr); 
       URL url = new URL(urlStr); 
       request(userInfo[1], userInfo[2], url, true); 
      } 

     } 

     @Test 
     public void testRequestAuthenticationRegistered() throws UnknownHostException, MalformedURLException { 

      Map<String, String[]> urls = generateURLs(); 

      for (String urlStr : urls.keySet()) { 
       String[] userInfo = urls.get(urlStr); 
       LOG.info("Testing: " + urlStr); 
       URL url = new URL(urlStr); 

       DefaultAuthenticator.reset(); 
       DefaultAuthenticator auth = DefaultAuthenticator.getInstance(); 

       String userName = userInfo[1]; 
       String password = userInfo[2]; 

       if (password != null) { 
        // You can't register a null password 
        auth.register(url, new PasswordAuthentication(userName, password.toCharArray())); 
       } 

       request(userName, password, url, false); 
      } 

     } 

     /** 
     * Generate a bunch of URLs mapped to String array. The String array has the following elements: 
     * - user info part of URL, 
     * - expected user, 
     * - expected password 
     * 
     * Note that the keys of the maps must be strings and not URL objects, because of the way URL.equals is 
     * implemented. This method does not consider the credentials. 
     * 
     * @throws MalformedURLException 
     */ 
     Map<String, String[]> generateURLs() { 
      String[] hosts = new String[]{ "127.0.0.1", "localhost.localdomain"}; 

      List<String[]> userData = new ArrayList<String[]>(); 

      // normal cases 
      userData.add(new String[] { "user:[email protected]", "user", "pass" }); // results in: http://user:[email protected][host] 
      userData.add(new String[] { "", null, null }); 
      // unexpected cases 
      userData.add(new String[] { "@", null, null }); 
      userData.add(new String[] { ":@", "", "" }); 
      userData.add(new String[] { "user:@", "user", "" }); 
      userData.add(new String[] { ":[email protected]", "", "pass" }); 

      Map<String, String[]> urls = new HashMap<String, String[]>(); 

      for (String[] userInfo : userData) { 
       for (String host : hosts) { 
        String s = "http://" + userInfo[0] + host; 
        urls.put(s, userInfo); 
       } 
      } 

      LOG.info("" + urls.size() + " URLs prepared"); 

      return urls; 
     } 

     private void request(String expectedUser, String expectedPass, URL url, boolean inURL) 
     throws UnknownHostException {   

      String host = url.getHost(); 
      InetAddress addr = InetAddress.getAllByName(host)[0]; 
      int port = url.getPort(); 
      String protocol = url.getProtocol(); 
      String prompt = ""; // prompt for the user when asking for the credentials 
      String scheme = "basic"; // or digest 
      RequestorType reqType = RequestorType.SERVER; 

      PasswordAuthentication credentials = 
       Authenticator.requestPasswordAuthentication(addr, port, protocol, prompt, scheme); 
      // If the credentials are in the URL, you can't find them using this method because we're not passing the URL 
      checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); 

      credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme); 
      // If the credentials are in the URL, you can't find them using this method because we're not passing the URL 
      checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); 

      credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme, url, reqType); 
      checkCredentials(url, expectedUser, expectedPass, credentials); 
     } 

     private void checkCredentials(URL url, String expectedUser, String expectedPass, PasswordAuthentication credentials) { 
      if (expectedUser == null) { 
       Assert.assertNull(url.toString(), credentials); 
      } else { 
       Assert.assertNotNull(url.toString(), credentials); 
       Assert.assertEquals(url.toString(), expectedUser, credentials.getUserName()); 

       if (expectedPass == null) { 
        Assert.assertNull(url.toString(), credentials.getPassword()); 
       } else { 
        Assert.assertArrayEquals(url.toString(), expectedPass.toCharArray(), credentials.getPassword()); 
       } 
      } 
     } 

    }