要验证请求,我使用Authenticator.setDefault
这是VM范围...
如果我想分开不同的Web服务怎么办?
并且每个人都知道他们的身份验证凭证
每个请求都需要Authenticator.setDefault
吗?
如果存在与混合Web服务的并发连接,则此操作可能无效...
答案 0 :(得分:3)
基于Mike上面的回答,我有以下解决方案,因为虽然我非常欣赏一般的想法(这就是我复制它的原因;-),但我发现它有一些问题:
以下解决方案我认为可以解决这些问题。
/**
* Authenticator which keeps credentials to be passed to the requestor based on authority of the requesting URL. The
* authority is <pre>user:password@host: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:password@host: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:pass@", "user", "pass" }); // results in: http://user:pass@[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[] { ":pass@", "", "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());
}
}
}
}
答案 1 :(得分: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/<url-path></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 :(得分:-1)
缺乏答案往往意味着没有人知道,这告诉我没有答案。
我一直想知道同样的事情,我认为答案是不能通过java.net完成。我认为您需要一次限制对一个服务器的http访问,或者查看其他软件包,例如org.apache.http.client。