Java: Handling cookies when logging in with POST
I'm having quite some trouble logging in to any site in Java. I'm using the default URLconnection POST request, but I'm unsure how to handle the cookies properly. I tried this guide: http://www.hccp.org/java-net-cookie-how-to.html But couldn't get it working. I've been trying basically for days now, and I really need help if anyone wants to help me.
I'll probably be told that it's messy and that I should use a custom library meant for this stuff. I tried downloading one but wasn't sure how to get it set up and working. I've been trying various things for hours now, and it just won't work. I'd rather do this with a standard URLconnection, but if anyone can help me get another library working that's better for this, that would be great, too.
I would really appreciate it if someone could post a working source that I could study. What I need is: POST login data to site -> Get and store the cookie from the site -> use a cookie with next URLconnection requests to get the logged-in version of the site.
Can anyone help me with this? Would be EXTREMELY appreciated. It really does mean a lot. If anyone wants to actually help me out live, please leave an instant-messenger address. Thank you a lot for your time.
package org.hccp.net;
import java.net.*;
import java.io.*;
import java.util.*;
import java.text.*;
/**
* CookieManager is a simple utilty for handling cookies when working
* with java.net.URL and java.net.URLConnection
* objects.
*
*
* Cookiemanager cm = new CookieManager();
* URL url = new URL("http://www.hccp.org/test/cookieTest.jsp");
*
* . . .
*
* // getting cookies:
* URLConnection conn = url.openConnection();
* conn.connect();
*
* // setting cookies
* cm.storeCookies(conn);
* cm.setCookies(url.openConnection());
*
* @author Ian Brown
*
**/
public class CookieManager {
private Map store;
private static final String SET_COOKIE = "Set-Cookie";
private static final String COOKIE_VALUE_DELIMITER = ";";
private static final String PATH = "path";
private static final String EXPIRES = "expires";
private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z";
private static final String SET_COOKIE_SEPARATOR="; ";
private static final String COOKIE = "Cookie";
private static final char NAME_VALUE_SEPARATOR = '=';
private static final char DOT = '.';
private DateFormat dateFormat;
public CookieManager() {
store = new HashMap();
dateFormat = new SimpleDateFormat(DATE_FORMAT);
}
/**
* Retrieves and stores cookies returned by the host on the other side
* of the the open java.net.URLConnection.
*
* The connection MUST have been opened using the connect()
* method or a IOException will be thrown.
*
* @param conn a java.net.URLConnection - must be open, or IOException will be thrown
* @throws java.io.IOException Thrown if conn is not open.
*/
public void storeCookies(URLConnection conn) throws IOException {
// let's determine the domain from where these cookies are being sent
String domain = getDomainFromHost(conn.getURL().getHost());
Map domainStore; // this is where we will store cookies for this domain
// now let's check the store to see if we have an entry for this domain
if (store.containsKey(domain)) {
// we do, so lets retrieve it from the store
domainStore = (Map)store.get(domain);
} else {
// we don't, so let's create it and put it in the store
domainStore = new HashMap();
store.put(domain, domainStore);
}
// OK, now we are ready to get the cookies out of the URLConnection
String headerName=null;
for (int i=1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) {
if (headerName.equalsIgnoreCase(SET_COOKIE)) {
Map cookie = new HashMap();
StringTokenizer st = new StringTokenizer(conn.getHeaderField(i), COOKIE_VALUE_DELIMITER);
// the specification dictates that the first name/value pair
// in the string is the cookie name and value, so let's handle
// them as a special case:
if (st.hasMoreTokens()) {
String token = st.nextToken();
String name = token.substring(0, token.indexOf(NAME_VALUE_SEPARATOR));
String value = token.substring(token.indexOf(NAME_VALUE_SEPARATOR) + 1, token.length());
domainStore.put(name, cookie);
cookie.put(name, value);
}
while (st.hasMoreTokens()) {
String token = st.nextToken();
cookie.put(token.substring(0, token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase(),
token.substring(token.indexOf(NAME_VALUE_SEPARATOR) + 1, token.length()));
}
}
}
}
/**
* Prior to opening a URLConnection, calling this method will set all
* unexpired cookies that match the path or subpaths for thi underlying URL
*
* The connection MUST NOT have been opened
* method or an IOException will be thrown.
*
* @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown
* @throws java.io.IOException Thrown if conn has already been opened.
*/
public void setCookies(URLConnection conn) throws IOException {
// let's determine the domain and path to retrieve the appropriate cookies
URL url = conn.getURL();
String domain = getDomainFromHost(url.getHost());
String path = url.getPath();
Map domainStore = (Map)store.get(domain);
if (domainStore == null) return;
StringBuffer cookieStringBuffer = new StringBuffer();
Iterator cookieNames = domainStore.keySet().iterator();
while(cookieNames.hasNext()) {
String cookieName = (String)cookieNames.next();
Map cookie = (Map)domainStore.get(cookieName);
// check cookie to ensure path matches and cookie is not expired
// if all is cool, add cookie to header string
if (comparePaths((String)cookie.get(PATH), path) && isNotExpired((String)cookie.get(EXPIRES))) {
cookieStringBuffer.append(cookieName);
cookieStringBuffer.append("=");
cookieStringBuffer.append((String)cookie.get(cookieName));
if (c开发者_开发知识库ookieNames.hasNext()) cookieStringBuffer.append(SET_COOKIE_SEPARATOR);
}
}
try {
conn.setRequestProperty(COOKIE, cookieStringBuffer.toString());
} catch (java.lang.IllegalStateException ise) {
IOException ioe = new IOException("Illegal State! Cookies cannot be set on a URLConnection that is already connected. "
+ "Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect().");
throw ioe;
}
}
private String getDomainFromHost(String host) {
if (host.indexOf(DOT) != host.lastIndexOf(DOT)) {
return host.substring(host.indexOf(DOT) + 1);
} else {
return host;
}
}
private boolean isNotExpired(String cookieExpires) {
if (cookieExpires == null) return true;
Date now = new Date();
try {
return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0;
} catch (java.text.ParseException pe) {
pe.printStackTrace();
return false;
}
}
private boolean comparePaths(String cookiePath, String targetPath) {
if (cookiePath == null) {
return true;
} else if (cookiePath.equals("/")) {
return true;
} else if (targetPath.regionMatches(0, cookiePath, 0, cookiePath.length())) {
return true;
} else {
return false;
}
}
/**
* Returns a string representation of stored cookies organized by domain.
*/
public String toString() {
return store.toString();
}
public static void main(String[] args) {
CookieManager cm = new CookieManager();
try {
URL url = new URL("http://www.hccp.org/test/cookieTest.jsp");
URLConnection conn = url.openConnection();
conn.connect();
cm.storeCookies(conn);
System.out.println(cm);
cm.setCookies(url.openConnection());
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
This code works for me:
Getting the login-form (in my case, the cookie is actually set when I retrieve the login-page)
URL url = new URL(formPage);
URLConnection conn = url.openConnection();
String cookieHeader = conn.getHeaderFields().get("Set-Cookie").get(0);
Matcher m = JSESSION_PATTERN.matcher(cookieHeader);
m.find();
jSessionId = m.group(1);
I also need to grab a csrf value as well, but I'll omit that now.
I then login by doing:
URL url = new URL(formPage);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Cookie", "JSESSIONID=" + encode(jSessionId, "UTF-8"));
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(String.format("_csrf_token=%s&xyz=%s&zyx=%s",
encode(csrfToken, "UTF-8"),
encode(USER, "UTF-8"),
encode(PASS, "UTF-8")));
out.close();
// I have absolutely no idea why this is needed.
conn.getInputStream().close();
String cookieHeader = conn.getHeaderFields().get("Set-Cookie").get(0);
Matcher m = JSESSION_PATTERN.matcher(cookieHeader);
m.find();
jSessionId = m.group(1);
I can then retrieve and process pages using
URL url = new URL(thePage);
URLConnection conn = url.openConnection();
conn.setRequestProperty("Cookie", "JSESSIONID=" + encode(jSessionId, "UTF-8"));
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String str;
while ((str = in.readLine()) != null) {
// process str...
Hope that helps!
精彩评论