如何在Web中将Cookie从WebViewClient持久化到URLConnection,浏览器或其他文件下载技术

All*_*ice 6 java cookies asp.net-mvc android forms-authentication

我们有一个.net表单启用auth启用的站点,用户通过我们的Android应用程序中的WebViewClient访问.该站点的一个功能是能够登录和下载某些PDF文件,但是您需要登录才能下载PDF.

我们正在实施shouldOverrideUrlLoading并在满足正确条件时通过以下代码下载pdf.

URL u = new URL(url);
URLConnection conn = u.openConnection();
int contentLength = conn.getContentLength();

DataInputStream stream = new DataInputStream(u.openStream());

byte[] buffer = new byte[contentLength];
stream.readFully(buffer);
stream.close();

DataOutputStream fos = new DataOutputStream(new FileOutputStream("/sdcard/download/file.pdf"));
fos.write(buffer);
fos.flush();
fos.close();
Run Code Online (Sandbox Code Playgroud)

从IIS日志中可以看出,IIS不会考虑将此请求登录并将其重定向到登录页面.

我们需要的是一种下载文件的方法,文件下载请求中保留了auth cookie,但我们不知道如何保留cookie.

对我们来说另一个可行的解决方案是在WebViewClient和Android浏览器之间保留auth cookie.如果我们可以这样做,我们只需通过浏览器中的默认操作打开PDF文件.

编辑:看起来我可以手动设置auth cookie

conn.setRequestProperty("Cookie", "");
Run Code Online (Sandbox Code Playgroud)

现在我只需要弄清楚如何从WebViewClient中读取auth cookie

All*_*ice 8

由于您使用的是ASP.NET Forms身份验证,因此您需要将表单auth cookie从中复制WebViewURLConnection.幸运的是,这很简单.此代码存在于一个实现中shouldOverrideUrlLoading

string url = "http://site/generatePdfBehindFormsAuth";

// get an instance of a cookie manager since it has access to our auth cookie
CookieManager cookieManager = CookieManager.getInstance();

// get the cookie string for the site.  This looks something like ".ASPXAUTH=data"
String auth = cookieManager.getCookie(url).toString();

URLConnection conn = (URLConnection)new URL(url).openConnection();

// Set the cookie string to be sent for download.  In our case we're just copying the
//   entire cookie string from the previous connection, so all values stored in 
//   cookies are persisted to this new connection.  This includes the aspx auth 
//   cookie, otherwise it would not be authenticated
//   when downloading the file.  
conn.setRequestProperty("Cookie", auth);
conn.setDoOutput(true);
conn.connect();

// get the filename from the servers response, its typical value is something like:
//   attachment; filename="GeneratedPDFFilename.pdf"
String filename = conn.getHeaderField("Content-Disposition").split("\"")[1];

// by default, we'll store the pdf in the external storage directory
String fileRoot = "/sdcard/";

// Complete the download
FileOutputStream f = new FileOutputStream(new File(fileRoot, filename));
InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) 
{
    f.write(buffer,0, len1);
}
f.close();
in.close();
Run Code Online (Sandbox Code Playgroud)

注意:有一点要注意的是,你应该拨打电话给getContentLengthURLConnection.经过4个小时的调试,wireshark最终表明,如果你打电话getContentLength,cookie将被发送给获取内容长度的请求,但是不会为后续请求发送cookie,即使在同一个URLConnection实例上也是如此.也许我天真,这是设计的(文档并没有表明它是按设计),但我无法通过调用setRequestProperty后调用手动设置后续文件请求的cookie getContentLength.如果我试图这样做,我会接近一个力量.