package net.dev123.commons.http.auth; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import net.dev123.commons.Constants; import net.dev123.commons.ServiceProvider; import net.dev123.commons.http.HttpMethod; import net.dev123.commons.http.HttpRequestHelper; import net.dev123.commons.http.HttpRequestMessage; import net.dev123.commons.oauth.OAuth; import net.dev123.commons.oauth.OAuthAccessToken; import net.dev123.commons.oauth.OAuthRequestToken; import net.dev123.commons.oauth.config.OAuthConfiguration; import net.dev123.commons.oauth.config.OAuthConfigurationFactory; import net.dev123.commons.util.StringUtil; import net.dev123.exception.ExceptionCode; import net.dev123.exception.LibException; import net.dev123.exception.LibRuntimeException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OAuthAuthorizeHelper { private ServiceProvider serviceProvider; private OAuthConfiguration oAuthConfig; private String consumerKey; private String consumerSecret; private String callbackUrl; public OAuthAuthorizeHelper(ServiceProvider serviceProvider) { if (serviceProvider == null) { throw new NullPointerException("ServiceProvider must not be null!"); } this.serviceProvider = serviceProvider; this.serviceProvider = serviceProvider; this.oAuthConfig = OAuthConfigurationFactory.getOAuthConfiguration(serviceProvider); this.consumerKey = oAuthConfig.getOAuthConsumerKey(); this.consumerSecret = oAuthConfig.getOAuthConsumerSecret(); this.callbackUrl = oAuthConfig.getOAuthCallbackURL(); } public void setConsumer(String consumerKey, String consumerSecret) throws LibException { if (StringUtil.isEmpty(consumerKey) || StringUtil.isEmpty(consumerSecret)) { throw new LibException(ExceptionCode.PARAMETER_NULL); } this.consumerKey = consumerKey; this.consumerSecret = consumerSecret; } public void setCallbackUrl(String callbackUrl) throws LibException { if (StringUtil.isEmpty(callbackUrl)) { throw new LibException(ExceptionCode.PARAMETER_NULL); } this.callbackUrl = callbackUrl; } /** * 获取RequestToken * * @return 获取RequestToken * @throws LibException * @see <a href="http://oauth.net/core/1.0a/#auth_step1">OAuth Core 1.0a - 6.1. * Obtaining an Unauthorized Request Token</a> */ public OAuthRequestToken retrieveOAuthRequestToken() throws LibException { OAuthAuthorization auth = new OAuthAuthorization(null, serviceProvider); auth.setConsumerKey(consumerKey); auth.setConsumerSecret(consumerSecret); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.GET, oAuthConfig.getOAuthRequestTokenURL(), auth); request.addParameter(OAuth.OAUTH_CALLBACK, callbackUrl); Map<String, String> responseMap = HttpRequestHelper.execute( request, new FormEncodedResponseHandler()); String token = responseMap.get(OAuth.OAUTH_TOKEN); String tokenSecret = responseMap.get(OAuth.OAUTH_TOKEN_SECRET); boolean isCallbackConfirmed = Boolean.valueOf(responseMap.get(OAuth.OAUTH_CALLBACK_CONFIRMED)); OAuthRequestToken requestToken = new OAuthRequestToken(token, tokenSecret); String userAuthorizationUrl = oAuthConfig.getOAuthAuthorizeURL(); StringBuilder authorizationUrl = new StringBuilder(userAuthorizationUrl); if (authorizationUrl.indexOf("?") < 0) { authorizationUrl.append("?"); } else { authorizationUrl.append("&"); } authorizationUrl.append(OAuth.OAUTH_TOKEN).append("=").append(token); if (!isCallbackConfirmed) { // 使用的是 OAuth 1.0 规定的callback传递方式,需要通过授权url参数传递 authorizationUrl.append("&"); authorizationUrl.append(OAuth.OAUTH_CALLBACK).append("=").append(callbackUrl); } requestToken.setAuthorizationURL(authorizationUrl.toString()); requestToken.setCallbackUrl(callbackUrl); return requestToken; } /** * 通过OAuthRquestToken和Verifier获取OAuthAccessToken * * @param requestToken * OAuth rquest token * @param oauthVerifier * OAuth verifier. AKA pin. * @return 与提供的OAuthRquestToken相关的OAuthAccessToken * @throws LibException * @see <a href="http://oauth.net/core/1.0a/#auth_step2">OAuth Core 1.0a - 6.2. * Obtaining User Authorization</a> */ public OAuthAccessToken retrieveOAuthAccessToken(OAuthRequestToken requestToken, String oauthVerifier) throws LibException { if (requestToken == null || StringUtil.isEmpty(oauthVerifier)) { throw new LibRuntimeException(ExceptionCode.PARAMETER_NULL); } OAuthAuthorization auth = new OAuthAuthorization(requestToken, serviceProvider); auth.setConsumerKey(consumerKey); auth.setConsumerSecret(consumerSecret); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.GET, oAuthConfig.getOAuthAccessTokenURL(), auth); request.addParameter(OAuth.OAUTH_VERIFIER, oauthVerifier); Map<String, String> responseMap = HttpRequestHelper.execute( request, new FormEncodedResponseHandler()); String token = responseMap.get(OAuth.OAUTH_TOKEN); String tokenSecret = responseMap.get(OAuth.OAUTH_TOKEN_SECRET); String userId = responseMap.get("user_id"); String username = responseMap.get("screen_name"); OAuthAccessToken accessToken = new OAuthAccessToken(token, tokenSecret); accessToken.setUserId(userId); accessToken.setUsername(username); return accessToken; } /** * 使用用户名和密码通过XAuth认证方式获取OAuthAccessToken.<br> * * @param username * 用户名 * @param password * 密码 * @return 获取到的OAuthAccessToken * @throws LibException */ public OAuthAccessToken retrieveOAuthAccessToken(String username, String password) throws LibException { OAuthAuthorization xAuth = new OAuthAuthorization(null, serviceProvider); xAuth.setConsumerKey(consumerKey); xAuth.setConsumerSecret(consumerSecret); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.POST, oAuthConfig.getOAuthAccessTokenURL(), xAuth); request.addParameter("x_auth_username", username); request.addParameter("x_auth_password", password); request.addParameter("x_auth_mode", "client_auth"); Map<String, String> xAuthResponse = HttpRequestHelper.execute( request, new FormEncodedResponseHandler()); String token = xAuthResponse.get(OAuth.OAUTH_TOKEN); String tokenSecret = xAuthResponse.get(OAuth.OAUTH_TOKEN_SECRET); String userId = xAuthResponse.get("user_id"); OAuthAccessToken accessToken = new OAuthAccessToken(token, tokenSecret); accessToken.setUserId(userId); accessToken.setUsername(username); return accessToken; } private class FormEncodedResponseHandler implements ResponseHandler<Map<String, String>> { private final Logger logger = LoggerFactory.getLogger(FormEncodedResponseHandler.class.getSimpleName()); @Override public Map<String, String> handleResponse(HttpResponse response) throws ClientProtocolException, IOException { StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() >= 300) { int statusCode = statusLine.getStatusCode(); if (statusCode == HttpStatus.SC_FORBIDDEN && (serviceProvider == ServiceProvider.Sina || serviceProvider == ServiceProvider.NetEase)) { //在使用XAuth认证方式下,若用户名或密码错误,新浪、网易的响应是403,搜狐的是401,统一为401 statusCode = HttpStatus.SC_UNAUTHORIZED; } if (serviceProvider == ServiceProvider.Tencent && HttpStatus.SC_BAD_REQUEST == statusCode && "Bad Request: Unsupported parameter".equals(statusLine.getReasonPhrase())){ statusCode = ExceptionCode.OAUTH_TIMESTAMP_REFUSED; } throw new LibRuntimeException(statusCode); } Map<String, String> resultMap = new HashMap<String, String>(); HttpEntity entity = response.getEntity(); final String responseString = EntityUtils.toString(entity); if (Constants.DEBUG) { logger.debug("FormEncodedResponseHandler : {}", responseString); } Scanner scanner = new Scanner(responseString); scanner.useDelimiter("&"); while (scanner.hasNext()) { final String[] nameValue = scanner.next().split("="); if (nameValue.length == 0 || nameValue.length > 2){ throw new LibRuntimeException(ExceptionCode.PARAMETER_ERROR, "", "Bad Parameter", ServiceProvider.None); } final String name = nameValue[0]; String value = null; if (nameValue.length == 2){ value = nameValue[1]; } resultMap.put(name, value); } return resultMap; } } public String getConsumerKey() { return consumerKey; } public String getConsumerSecret() { return consumerSecret; } }