@@ -128,4 +128,12 @@ public class WxConsts { | |||
/** 弹出地理位置选择器 */ | |||
public static final String LOCATION_SELECT = "location_select"; | |||
/////////////////////// | |||
// oauth2网页授权的scope | |||
/////////////////////// | |||
/** 不弹出授权页面,直接跳转,只能获取用户openid */ | |||
public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | |||
/** 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 */ | |||
public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo"; | |||
} |
@@ -0,0 +1,47 @@ | |||
package me.chanjar.weixin.common.util.http; | |||
import me.chanjar.weixin.common.util.StringUtils; | |||
import java.io.UnsupportedEncodingException; | |||
public class URIUtil { | |||
private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; | |||
public static String encodeURIComponent(String input) { | |||
if (StringUtils.isEmpty(input)) { | |||
return input; | |||
} | |||
int l = input.length(); | |||
StringBuilder o = new StringBuilder(l * 3); | |||
try { | |||
for (int i = 0; i < l; i++) { | |||
String e = input.substring(i, i + 1); | |||
if (ALLOWED_CHARS.indexOf(e) == -1) { | |||
byte[] b = e.getBytes("utf-8"); | |||
o.append(getHex(b)); | |||
continue; | |||
} | |||
o.append(e); | |||
} | |||
return o.toString(); | |||
} catch (UnsupportedEncodingException e) { | |||
e.printStackTrace(); | |||
} | |||
return input; | |||
} | |||
private static String getHex(byte buf[]) { | |||
StringBuilder o = new StringBuilder(buf.length * 3); | |||
for (int i = 0; i < buf.length; i++) { | |||
int n = (int) buf[i] & 0xff; | |||
o.append("%"); | |||
if (n < 0x10) { | |||
o.append("0"); | |||
} | |||
o.append(Long.toString(n, 16).toUpperCase()); | |||
} | |||
return o.toString(); | |||
} | |||
} |
@@ -25,6 +25,8 @@ public interface WxMpConfigStorage { | |||
public int getExpiresIn(); | |||
public String getOauth2redirectUrl(); | |||
public String getHttp_proxy_host(); | |||
public int getHttp_proxy_port(); | |||
@@ -20,6 +20,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
protected int http_proxy_port; | |||
protected String http_proxy_username; | |||
protected String http_proxy_password; | |||
protected String oauth2redirectUrl; | |||
public void updateAccessToken(WxAccessToken accessToken) { | |||
updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); | |||
@@ -78,6 +79,15 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
this.expiresIn = expiresIn; | |||
} | |||
@Override | |||
public String getOauth2redirectUrl() { | |||
return this.oauth2redirectUrl; | |||
} | |||
public void setOauth2redirectUrl(String oauth2redirectUrl) { | |||
this.oauth2redirectUrl = oauth2redirectUrl; | |||
} | |||
public String getHttp_proxy_host() { | |||
return http_proxy_host; | |||
} | |||
@@ -329,6 +329,54 @@ public interface WxMpService { | |||
*/ | |||
WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 构造oauth2授权的url连接 | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 | |||
* </pre> | |||
* @param scope | |||
* @param state | |||
* @return code | |||
*/ | |||
public String oauth2buildAuthorizationUrl(String scope, String state); | |||
/** | |||
* <pre> | |||
* 用code换取oauth2的access token | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 | |||
* </pre> | |||
* @param code | |||
* @return | |||
*/ | |||
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 刷新oauth2的access token | |||
* </pre> | |||
* @param refreshToken | |||
* @return | |||
*/ | |||
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以 | |||
* </pre> | |||
* @param oAuth2AccessToken | |||
* @param lang zh_CN, zh_TW, en | |||
*/ | |||
public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 验证oauth2的access token是否有效 | |||
* </pre> | |||
* @param oAuth2AccessToken | |||
* @return | |||
*/ | |||
public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); | |||
/** | |||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | |||
* @param url | |||
@@ -27,11 +27,13 @@ import org.apache.http.client.CredentialsProvider; | |||
import org.apache.http.client.config.RequestConfig; | |||
import org.apache.http.client.methods.CloseableHttpResponse; | |||
import org.apache.http.client.methods.HttpGet; | |||
import org.apache.http.client.utils.URIUtils; | |||
import org.apache.http.impl.client.BasicCredentialsProvider; | |||
import org.apache.http.impl.client.BasicResponseHandler; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.apache.http.impl.client.HttpClients; | |||
import javax.print.DocFlavor; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -297,6 +299,98 @@ public class WxMpServiceImpl implements WxMpService { | |||
return WxMpSemanticQueryResult.fromJson(responseContent); | |||
} | |||
@Override | |||
public String oauth2buildAuthorizationUrl(String scope, String state) { | |||
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" ; | |||
url += "appid=" + wxMpConfigStorage.getAppId(); | |||
url += "&redirect_uri=" + URIUtil.encodeURIComponent(wxMpConfigStorage.getOauth2redirectUrl()); | |||
url += "&response_type=code"; | |||
url += "&scope=" + scope; | |||
if (state != null) { | |||
url += "&state=" + state; | |||
} | |||
url += "#wechat_redirect"; | |||
return url; | |||
} | |||
@Override | |||
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"; | |||
url += "appid=" + wxMpConfigStorage.getAppId(); | |||
url += "&secret=" + wxMpConfigStorage.getSecret(); | |||
url += "&code=" + code; | |||
url += "&grant_type=authorization_code"; | |||
try { | |||
RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | |||
String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||
return WxMpOAuth2AccessToken.fromJson(responseText); | |||
} catch (ClientProtocolException e) { | |||
throw new RuntimeException(e); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
@Override | |||
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?"; | |||
url += "appid=" + wxMpConfigStorage.getAppId(); | |||
url += "&grant_type=refresh_token"; | |||
url += "&refresh_token=" + refreshToken; | |||
try { | |||
RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | |||
String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||
return WxMpOAuth2AccessToken.fromJson(responseText); | |||
} catch (ClientProtocolException e) { | |||
throw new RuntimeException(e); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
@Override | |||
public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/sns/userinfo?"; | |||
url += "access_token=" + oAuth2AccessToken.getAccessToken(); | |||
url += "&openid=" + oAuth2AccessToken.getOpenId(); | |||
if (lang == null) { | |||
url += "&lang=zh_CN"; | |||
} else { | |||
url += "&lang=" + lang; | |||
} | |||
try { | |||
RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | |||
String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||
return WxMpUser.fromJson(responseText); | |||
} catch (ClientProtocolException e) { | |||
throw new RuntimeException(e); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
@Override | |||
public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { | |||
String url = "https://api.weixin.qq.com/sns/auth?"; | |||
url += "access_token=" + oAuth2AccessToken; | |||
url += "&openid=" + oAuth2AccessToken.getOpenId(); | |||
try { | |||
RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | |||
executor.execute(getHttpclient(), httpProxy, url, null); | |||
} catch (ClientProtocolException e) { | |||
throw new RuntimeException(e); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} catch (WxErrorException e) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
public String get(String url, String queryParam) throws WxErrorException { | |||
return execute(new SimpleGetRequestExecutor(), url, queryParam); | |||
} | |||
@@ -0,0 +1,64 @@ | |||
package me.chanjar.weixin.mp.bean.result; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
/** | |||
* Created by qianjia on 14/11/26. | |||
*/ | |||
public class WxMpOAuth2AccessToken { | |||
private String accessToken; | |||
private int expiresIn = -1; | |||
private String refreshToken; | |||
private String openId; | |||
private String scope; | |||
public String getRefreshToken() { | |||
return refreshToken; | |||
} | |||
public void setRefreshToken(String refreshToken) { | |||
this.refreshToken = refreshToken; | |||
} | |||
public String getOpenId() { | |||
return openId; | |||
} | |||
public void setOpenId(String openId) { | |||
this.openId = openId; | |||
} | |||
public String getScope() { | |||
return scope; | |||
} | |||
public void setScope(String scope) { | |||
this.scope = scope; | |||
} | |||
public String getAccessToken() { | |||
return accessToken; | |||
} | |||
public void setAccessToken(String accessToken) { | |||
this.accessToken = accessToken; | |||
} | |||
public int getExpiresIn() { | |||
return expiresIn; | |||
} | |||
public void setExpiresIn(int expiresIn) { | |||
this.expiresIn = expiresIn; | |||
} | |||
public static WxMpOAuth2AccessToken fromJson(String json) { | |||
return WxGsonBuilder.create().fromJson(json, WxMpOAuth2AccessToken.class); | |||
} | |||
} |