【问题标题】:How to handle Basic Authentication in WebView如何在 WebView 中处理基本身份验证
【发布时间】:2010-11-18 23:42:59
【问题描述】:

我创建了一个加载 WebView 的应用程序。为了登录, 该网站需要基本身份验证。当我尝试访问该网站时 通过默认浏览器,我得到一个弹出框,提示我输入我的用户名 和密码。

如果我尝试通过我的应用程序访问该网站,我会收到错误 401 并且没有弹出窗口。 我想知道是否有人可以帮助我?

【问题讨论】:

    标签: android android-webview


    【解决方案1】:

    我认为比 Patrick 描述的更优雅的解决方案是使用 WebViewClient 的 onReceivedHttpAuthRequest 方法,如下所述:http://www.mail-archive.com/android-developers@googlegroups.com/msg30468.html

    @Override
    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
        handler.proceed("username", "password");
    }
    

    【讨论】:

    • 这样不行了,方法好像不存在了。
    • 对于上面的代码,你必须删除 super。 onReceivedHttpAuthRequest()。否则它将调用handle.cancel,这会使您的代码无法正常工作。
    【解决方案2】:

    该网站需要身份验证。

    首先你对错误做出反应:

    webview.setWebViewClient(new WebViewClient() {
       public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
         if (errorCode == 401) {
             // show alert to enter username and password
             // then when those are entered in the alert,
             //     set it through the setHttpAuthUsernamePassword(...) shown below
             //     and then reload the site
         }
       }
     });
    

    使用此功能设置用户和密码:WebView.setHttpAuthUsernamePassword()

    webview.setHttpAuthUsernamePassword(host, realm, username, password);
    

    都是字符串。有关主机和领域含义的更多信息,请参阅上面的链接。

    在这里找到解决方案:Supply some basic auth credentials to a WebView?

    【讨论】:

    • 感谢大家的快速回复。如果我错了,请纠正我,但不会 webview.setHttpAuthUsernamePassword(host, realm, username, password);要求我在代码中预定义用户名和密码?我试图弄清楚如何让应用程序像默认浏览器一样弹出用户名/登录框..
    • 好的.. 将在我的帖子中添加解释如何做到这一点.. 等一下。
    • 再次感谢!我仍然收到 401,但我会继续尝试让它发挥作用。
    【解决方案3】:

    这对我有用,添加用户名/传递 WebViewClient 然后 setWebViewClient

    webView.setWebViewClient(new MyWebViewClient ());
    
    //add this class in main activity 
    class MyWebViewClient extends WebViewClient {
        @Override
        public void onReceivedHttpAuthRequest(WebView view,
                                              HttpAuthHandler handler, String host, String realm) {
    
            handler.proceed("your username", "your password");
    
        }
    }
    

    【讨论】:

      【解决方案4】:

      我知道这很旧,但是在此处添加另一种方法(使用 onReceivedHttpAuthRequest)对我不起作用。具体来说,一些网页不会提示用户进行基本身份验证,它们只是重定向到登录屏幕。在我的测试中,Grafana 恰好默认有这种行为。

      因此,我使用以下代码添加了 HTTP Basic auth 标头:

      HashMap<String, String> headers = new HashMap<>();
      String basicAuthHeader = android.util.Base64.encodeToString((username + ":" + password).getBytes(), android.util.Base64.NO_WRAP);
      headers.put("Authorization", "Basic " + basicAuthHeader);
      webView.loadUrl(url, headers);
      

      这应该绕过身份验证提示并自动设置凭据。希望这对寻找其他解决方案的人有所帮助。

      此外,对于任何希望使用“https://username:password@url” URL 模式的人 - 这已被弃用,我认为大多数浏览器会忽略它并丢弃凭据。

      编辑

      我已经意识到我的上述解决方案仅适用于第一个请求,并且在页面加载后没有后续请求(即对于任何进一步加载的资源)。

      为了让所有后续请求都能正常工作,我必须为 Web 客户端覆盖以下函数:

      @Override
      public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request){
          if (username != null && password != null && username.length() > 0 && password.length() > 0) {
              try {
                  OkHttpClient client = new OkHttpClient();
                  Request.Builder newRequestBuilder = new Request.Builder()
                          .url(request.getUrl().toString());
      
                  // add headers
                  Map<String, String> currentHeaders = request.getRequestHeaders();
                  for (String header : currentHeaders.keySet()){
                      newRequestBuilder.addHeader(header, currentHeaders.get(header));
                  }
                  String basicAuthHeader = android.util.Base64.encodeToString((username + ":" + password).getBytes(), android.util.Base64.NO_WRAP);
                  newRequestBuilder.addHeader("Authorization", "Basic "+basicAuthHeader);
      
                  //make request
                  Request newRequest = newRequestBuilder.build();
                  Response response = client.newCall(newRequest).execute();
      
                  // respond with content
                  return new WebResourceResponse(response.header("content-type"), response.header("content-encoding", "utf-8"), response.body().byteStream());
              } catch (Exception e) {
                  // if an exception occurs, just make a default request
                  return null;
              }
          } else {
              // if no username and password, then make a default request
              return null;
          }
      }
      

      不幸的是,这段代码不会拦截 POST 请求,只会拦截 GET 请求,这限制了你可以用它做什么。

      此外,上述代码应添加一些逻辑,以在附加授权标头之前验证初始请求的域与拦截请求的域匹配。否则,授权标头将与所有可能无意将其发送到不同域的请求一起发送(例如,从 CDN 加载资源)。​​

      【讨论】:

        【解决方案5】:
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
             handler.proceed("USERNAME", "PASSWORD");
        }
        

        我认为它对 WebView 上的 401 错误很有帮助。

        【讨论】:

        • 我试过这个方法,结果一团糟。我强烈反对使用这种方法。如果您提供了错误的用户名或密码,则身份验证将失败,并且 webview 会继续重试身份验证。这是在我的服务器上创建重复的 api 调用,最终导致服务器宕机。您可以考虑使用计数器和 stopLoading() 方法来避免无限循环。
        【解决方案6】:

        使用这个函数onReceivedHttpAuthRequest。它通知主机应用程序 WebView 收到了 HTTP 身份验证请求。宿主应用程序可以使用提供的 HttpAuthHandler 来设置 WebView 对请求的响应。默认行为是取消请求。

        下面是用 Kotlin

        编写的示例
         override fun onReceivedHttpAuthRequest(
                    view: WebView,
                    handler: HttpAuthHandler,
                    host: String,
                    realm: String
                ) {
                    handler.proceed("username", "password")
                }
        

        Check the Documentation here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-27
          • 1970-01-01
          • 2021-10-10
          • 1970-01-01
          • 1970-01-01
          • 2013-03-19
          相关资源
          最近更新 更多