package org.yoshiori.hatena.auth; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.Arrays; import java.util.Map; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.yoshiori.commons.security.MessageDigest; import org.yoshiori.commons.security.MessageDigest.DigestAlgorithm; import org.yoshiori.hatena.HatenaException; /** *

はてな認証を行うクラスです.
* はてな認証の詳細については「はてな認証API」こちらをご覧ください。

* *

主な使い方としては
*

 HatenaAuth auth = new HatenaAuth("api_key", "secret");
 * String link = auth.getAuthURL();

* で、認証用のURLが取得できます。
* cert取得後、
*
User user =  auth.login(cert);

* でユーザー情報を取得できます。

* * @author yoshiori * @see はてな認証API */ public class HatenaAuth { private String apiKey; private String secret; private MessageDigest md5; private String encode = "UTF-8"; private static final String AUTH_URL = "http://auth.hatena.ne.jp/auth?"; private static final String LOGIN_URL = "http://auth.hatena.ne.jp/api/auth.xml?"; /** * @param apiKey はてなから取得したAPIキー * @param secret はてなから取得した秘密鍵 */ public HatenaAuth(String apiKey, String secret) { if(StringUtils.isEmpty(apiKey) || StringUtils.isEmpty(secret) ){ throw new NullPointerException("apikey or secret is null."); } this.apiKey = apiKey; this.secret = secret; md5 = new MessageDigest(DigestAlgorithm.MD5); } /** * apiKeyとsecretを元に * 認証用のURLが取得できます。 * @return 認証用URL */ public String getAuthURL() { return getAuthURL(null); } /** * apiKeyとsecretとparameterMapを元に * 認証用のURLが取得できます。
* parameterMapについては
* javax.servlet.ServletRequest.getParameterMap()
* 準じています。 * @param parameterMap 上記参照 * @return 認証用URL * @see javax.servlet.ServletRequest.getParameterMap() */ public String getAuthURL(Map parameterMap) { Map params = new TreeMap(); if(parameterMap != null){ params.putAll(parameterMap); } params.put("api_key", new String[] { apiKey }); StringBuilder sigBuilder = new StringBuilder(secret); StringBuilder paramBuilder = new StringBuilder(); for (String key : params.keySet()) { String[] parameterValues = params.get(key); Arrays.sort(parameterValues); for (String value : parameterValues) { sigBuilder.append(key).append(value); try { paramBuilder.append("&") .append(key) .append("=") .append(URLEncoder.encode(value, encode)); } catch (UnsupportedEncodingException e) { throw new HatenaException(e); } } } String sig = md5.getHexString(sigBuilder.toString()); return AUTH_URL + "api_sig=" + sig + paramBuilder.toString(); } /** * certを元にユーザーデータを取得します。 * @param cert 認証ハンドラから取得したcert の値 * @return {@link User} はてなユーザーデータ */ public User login(String cert){ if (cert == null) { throw new NullPointerException("cert is null"); } StringBuilder sigBuilder = new StringBuilder(secret); sigBuilder.append("api_key").append(apiKey); sigBuilder.append("cert").append(cert); String sig = md5.getHexString(sigBuilder.toString()); URL url = null; try { url = new URL(LOGIN_URL + "api_key=" + apiKey + "&cert=" + cert + "&api_sig=" + sig); } catch (MalformedURLException e) { throw new HatenaException(e); } SAXReader xmlReader = new SAXReader(); try { return getUser(xmlReader.read(url)); } catch (DocumentException e) { throw new HatenaException(e); } } /** * @param document * @return * @throws LoginException */ protected User getUser(Document document) { User user = new User(); Element root = document.getRootElement(); if ("true".equals(root.elementText("has_error"))) { throw new HatenaException(root.element("error").elementText("message")); } Element userElement = root.element("user"); user.setName(userElement.elementText("name")); user.setImageURL(userElement.elementText("image_url")); user.setThumbnailURL(userElement.elementText("thumbnail_url")); return user; } /** * @return */ public String getEncode() { return encode; } /** * @param encode パラメータの文字コード(デフォルトはUTF-8) */ public void setEncode(String encode) { this.encode = encode; this.md5.setEncoding(encode); } }