为什么 getPasswordAuthentication() 没有被调用?

4
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;

import sun.net.www.protocol.http.AuthCacheImpl;
import sun.net.www.protocol.http.AuthCacheValue;



public class RunHttpSpnego {
  public static void main(String args[]) throws MalformedURLException,
      IOException {
    String urlString = "http://www.yahoo.com";
    String username = "XXXXXXXXX";
    String password = "XXXXXXXX";
     // This is modified after the question is being asked. Now this code works fine
     System.setProperty("http.proxyHost","176.x.xx.xx") ;
    System.setProperty("http.proxyPort", "8080") ;

    Authenticator.setDefault(new MyAuthenticator(username, password));


    URL url = new URL(urlString);
    InputStream content = (InputStream) url.getContent();
    BufferedReader in = new BufferedReader(new InputStreamReader(content));
    String line;
    while ((line = in.readLine()) != null) {
      System.out.println(line);
    }
    System.out.println("Done.");
  }

  static class MyAuthenticator extends Authenticator {
    private String username, password;

    public MyAuthenticator(String user, String pass) {
      username = user;
      password = pass;
    }

    protected PasswordAuthentication getPasswordAuthentication() {
      System.out.println("Requesting Host  : " + getRequestingHost());
      System.out.println("Requesting Port  : " + getRequestingPort());
      System.out.println("Requesting Prompt : " + getRequestingPrompt());
      System.out.println("Requesting Protocol: "
          + getRequestingProtocol());
      System.out.println("Requesting Scheme : " + getRequestingScheme());
      System.out.println("Requesting Site  : " + getRequestingSite());
      return new PasswordAuthentication(username, password.toCharArray());
    }
  }
}

-- 现在我该检查什么,getPasswordAuthentication根本没有被调用?我确定我的IE启用了身份验证,但不确定是哪种类型的身份验证。


1
你确定服务器要求输入密码吗?这种服务只适用于HTTP密码,而不是Web表单中的密码。 - Erich Kitzmueller
你可以检查头部并找出认证类型是什么。 - NullUserException
是的,这是IE的入口密码。服务器每次访问互联网时都需要密码,所以我必须输入用户名和密码才能在Internet Explorer中连接到互联网。 - srinannapa
1
@srin 请查看BalusC在他的回答中的评论。这样做行不通。 - NullUserException
是的,我们需要代理,我修改了上面的代码,使其不会出错。 - srinannapa
请检查我的答案:https://dev59.com/rEbRa4cB1Zd3GeqPzVnJ#15904385 - Boris R.
8个回答

5
Authenticator 只用于使用基本HTTP身份验证的网站(这些网站通常会出现JavaScript样式的登录/密码弹出窗口),而不是使用基于表单的身份验证的网站(一个基于HTML的包含登录和密码字段的<form>通常具有炫酷的标记/样式),也不是拨号式的ISP登录。对于前者,您实际上需要将登录作为查询字符串传递,而对于后者,您实际上需要手动连接ISP或创建/使用代理。

请查看问题下面的注释。 - srinannapa
认证器不应用作您的ISP的登录密码。它是用于使用基本HTTP身份验证的网站。这是两个完全不同的事情。您在这里需要一个代理。 - BalusC
如果服务器发送 HTTP 401,但没有 WWW-Authenticate 标头,则 Authenticator 也不会被调用。 - mhaller
我收到一个带有WWW-Authenticate头值为NTLM的HTTP 401错误。但是Authenticator.getpasswordauthentication()仍未被调用。 - Soorya Chandrasekaran

2

Sun.net.www.protocol.http.ntlm.NTLMAuthentication试图使用透明身份验证,即使用当前用户凭据登录远程服务器。在我的服务器到服务器场景中(Java EE服务器到Sharepoint),这是不可接受的。为了禁用透明身份验证,我们需要让身份验证提供程序知道连接不受信任,并且每次调用都需要进行身份验证:

static {
    NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback()
    {
        @Override
        public boolean isTrustedSite(URL url)
        {
            return false;
        }
    });
}  

1
它也可能是服务器端需要预先身份验证并直接返回405错误响应。标准的HTTP基本身份验证如下: 1. 客户端发送没有身份验证信息的请求。 2. 服务器返回401。 3. 客户端重新发送带有身份验证信息的请求。 4. 服务器返回200。 对于预先身份验证: 1. 客户端发送没有身份验证信息的请求。 2. 服务器返回405,因为没有身份验证信息,所以不会调用getPasswordAuthentication()。 解决这种情况的方法是对用户名:密码进行编码,并将其放入“Authorization”头中。(例如:Authorization: Basic sldsfkjdsfjosdfjosjsdfs)

0

我在使用默认的http处理程序时,在12.1.1版本中遇到了与java.net.Authenticator不兼容的问题,可能有两种解决方法:

选项1,使用URL上的http授权来避免java.net.Authenticator。

HttpURLConnection uc = null;
URL url = new URL(server_URL);
uc = (HttpURLConnection) url.openConnection();
String userPassword = myaccount + ":" + mypassword;
String encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes());
uc.setRequestProperty("Authorization", "Basic " + encoding);

选项2,通过配置HTTP Handler保持使用java.net.Authenticator

Authenticator.setDefault(new MyAuthenticator());

URL url = new URL(null, service_URL, new sun.net.www.protocol.http.Handler());
uc = (HttpURLConnection) url.openConnection();

否则,您可能可以在客户端或服务器中将Sun HTTP处理程序配置为Weblogic 12c,但我忘记了如何使其工作,因为这可能会对在此服务器上运行的其他应用程序造成风险,我不建议在此处尝试。


0

试试这个替代方案

    DefaultHttpClient http = new DefaultHttpClient();
    final String username = "xxxx";
    final String password = "xxxx";
    UsernamePasswordCredentials c = new UsernamePasswordCredentials(username,password);
    BasicCredentialsProvider cP = new BasicCredentialsProvider(); 
    cP.setCredentials(AuthScope.ANY, c); 
    http.setCredentialsProvider(cP);

    HttpResponse res;

尝试这个而不是为什么? - user207421

0

getPasswordAuthentication() 没有被调用,因为 Authenticator 缓存了成功的身份验证尝试,并在未来的请求中使用缓存,除非您调用 Authenticator.setDefault(null) 来删除它。


-2

使用需要登录的URL。在您的情况下,您可以将雅虎的URL更改为

https://login.yahoo.com/config/login_verify2?&.src=ym

-3
如果getPasswordAuthentication()是一个实际的方法而不仅仅是你需要发生的事情,那么它实际上并不是你代码中的一行。我会假设你的意思是在这一行之后调用它:
Authenticator.setDefault(new MyAuthenticator(username, password));

我看到它被声明了但从未被调用。


如果服务器请求身份验证,它会自动调用。 - NullUserException

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