View Javadoc
1   package com.foxinmy.weixin4j.mp.api;
2   
3   import java.io.UnsupportedEncodingException;
4   import java.net.URLEncoder;
5   
6   import com.alibaba.fastjson.JSONObject;
7   import com.alibaba.fastjson.TypeReference;
8   import com.foxinmy.weixin4j.exception.WeixinException;
9   import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
10  import com.foxinmy.weixin4j.model.WeixinAccount;
11  import com.foxinmy.weixin4j.mp.model.OauthToken;
12  import com.foxinmy.weixin4j.mp.model.User;
13  import com.foxinmy.weixin4j.mp.type.Lang;
14  import com.foxinmy.weixin4j.util.Consts;
15  import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
16  
17  /**
18   * oauth授权
19   *
20   * @className OauthApi
21   * @author jinyu(foxinmy@gmail.com)
22   * @date 2015年3月6日
23   * @since JDK 1.6
24   */
25  public class OauthApi extends MpApi {
26  
27  	private final WeixinAccount account;
28  
29  	/**
30  	 * 默认使用weixin4j.properties里面的appid、appsecret信息
31  	 */
32  	public OauthApi() {
33  		this(Weixin4jConfigUtil.getWeixinAccount());
34  	}
35  
36  	/**
37  	 * 传入appid、appsecret信息
38  	 *
39  	 * @param account
40  	 */
41  	public OauthApi(WeixinAccount account) {
42  		this.account = account;
43  	}
44  
45  	/**
46  	 * 公众号网页获取用户资料oauth授权:请求code<li>
47  	 * redirectUri默认填写weixin4j.properties#user.oauth.redirect.uri <li>
48  	 * scope默认填写snsapi_base <li>
49  	 * state默认填写state
50  	 *
51  	 * @see {@link #getUserAuthorizationURL(String, String,String)}
52  	 *
53  	 * @return 请求授权的URL
54  	 */
55  	public String getUserAuthorizationURL() {
56  		String redirectUri = Weixin4jConfigUtil
57  				.getValue("user.oauth.redirect.uri");
58  		return getUserAuthorizationURL(redirectUri, "state", "snsapi_base");
59  	}
60  
61  	/**
62  	 * 公众号网页获取用户资料oauth授权:请求code
63  	 *
64  	 * @param redirectUri
65  	 *            重定向地址<br>
66  	 *            1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的开发者中心页配置授权回调域名。请注意,
67  	 *            这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;<br>
68  	 *            2、授权回调域名配置规范为全域名,比如需要网页授权的域名为
69  	 *            :www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html
70  	 *            http://www.qq.com/login.html<br>
71  	 *            都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、
72  	 *            http://qq.com无法进行OAuth2.0鉴权<br>
73  	 *            3、如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可
74  	 * @param state
75  	 *            用于保持请求和回调的状态,授权请求后原样带回给第三方
76  	 * @param scope
77  	 *            应用授权作用域,snsapi_base
78  	 *            (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo
79  	 *            (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)<br>
80  	 *            1、 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,
81  	 *            并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)<br>
82  	 *            2、以snsapi_userinfo为scope发起的网页授权
83  	 *            ,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过
84  	 *            ,所以无须关注,就可在授权后获取该用户的基本信息。<br>
85  	 *            3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后
86  	 *            ,才能根据用户OpenID来获取用户基本信息
87  	 *            ,这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。<br>
88  	 * @return 请求授权的URL
89  	 */
90  	public String getUserAuthorizationURL(String redirectUri, String state,
91  			String scope) {
92  		String sns_user_auth_uri = getRequestUri("sns_user_auth_uri");
93  		try {
94  			return String.format(sns_user_auth_uri, account.getId(),
95  					URLEncoder.encode(redirectUri, Consts.UTF_8.name()), scope,
96  					state);
97  		} catch (UnsupportedEncodingException e) {
98  			;
99  		}
100 		return "";
101 	}
102 
103 	/**
104 	 * 公众号网页获取用户资料oauth授权:code换取token
105 	 *
106 	 * @param code
107 	 *            用户同意授权获取的code,
108 	 *            code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次
109 	 *            ,5分钟未被使用自动过期。
110 	 * @return oauthtoken信息
111 	 * @see #getUserAuthorizationURL(String, String,String)
112 	 * @see #getAuthorizationUser(OauthToken)
113 	 */
114 	public OauthToken getAuthorizationToken(String code) throws WeixinException {
115 		String user_token_uri = getRequestUri("sns_user_token_uri");
116 		WeixinResponse response = weixinExecutor.get(String.format(
117 				user_token_uri, account.getId(), account.getSecret(), code));
118 		JSONObject result = response.getAsJson();
119 		OauthToken token = new OauthToken(result.getString("access_token"),
120 				result.getLongValue("expires_in") * 1000l);
121 		token.setUnionId(result.getString("unionid"));
122 		token.setOpenId(result.getString("openid"));
123 		token.setScope(result.getString("scope"));
124 		token.setRefreshToken(result.getString("refresh_token"));
125 		return token;
126 	}
127 
128 	/**
129 	 * 公众号网页获取用户资料oauth授权:刷新token,由于access_token拥有较短的有效期,当access_token超时后,
130 	 * 可以使用refresh_token进行刷新, refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。
131 	 *
132 	 *
133 	 * @param refreshToken
134 	 *            填写通过access_token获取到的refresh_token参数
135 	 * @see {@link #getAuthorizationToken(String)}
136 	 * @see com.foxinmy.weixin4j.mp.model.OauthToken
137 	 * @return oauthtoken信息
138 	 */
139 	public OauthToken refreshAuthorizationToken(String refreshToken)
140 			throws WeixinException {
141 		String sns_token_refresh_uri = getRequestUri("sns_token_refresh_uri");
142 		WeixinResponse response = weixinExecutor.get(String.format(
143 				sns_token_refresh_uri, account.getId(), refreshToken));
144 		JSONObject result = response.getAsJson();
145 		OauthToken token = new OauthToken(result.getString("access_token"),
146 				result.getLongValue("expires_in") * 1000l);
147 		token.setUnionId(result.getString("unionid"));
148 		token.setOpenId(result.getString("openid"));
149 		token.setScope(result.getString("scope"));
150 		token.setRefreshToken(result.getString("refresh_token"));
151 		return token;
152 	}
153 
154 	/**
155 	 * 验证access_token是否正确
156 	 *
157 	 * @param oauthToken
158 	 *            接口调用凭证
159 	 * @param openId
160 	 *            用户标识
161 	 * @return 验证结果
162 	 */
163 	public boolean verifyAuthorizationToken(String oauthToken, String openId) {
164 		String sns_auth_token_uri = getRequestUri("sns_auth_token_uri");
165 		try {
166 			weixinExecutor.get(String.format(sns_auth_token_uri, oauthToken,
167 					openId));
168 			return true;
169 		} catch (WeixinException e) {
170 			;
171 		}
172 		return false;
173 	}
174 
175 	/**
176 	 * oauth授权获取用户信息(需scope为 snsapi_userinfo)
177 	 *
178 	 * @param token
179 	 *            授权信息(token&openid)
180 	 * @return 用户对象
181 	 * @throws WeixinException
182 	 * @see <a
183 	 *      href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN">授权获取用户信息</a>
184 	 * @see com.foxinmy.weixin4j.mp.model.User
185 	 * @see com.foxinmy.weixin4j.mp.model.OauthToken
186 	 * @see {@link #getAuthorizationUser(String,Sring,Lang)}
187 	 */
188 	public User getAuthorizationUser(OauthToken token) throws WeixinException {
189 		return getAuthorizationUser(token.getAccessToken(), token.getOpenId(),
190 				Lang.zh_CN);
191 	}
192 
193 	/**
194 	 * oauth获取用户信息(需scope为 snsapi_userinfo)
195 	 *
196 	 * @param oauthToken
197 	 *            授权票据
198 	 * @param openid
199 	 *            用户openid
200 	 * @param lang
201 	 *            使用语言
202 	 * @return 用户对象
203 	 * @throws WeixinException
204 	 * @see <a
205 	 *      href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN">授权获取用户信息</a>
206 	 * @see {@link #getAuthorizationToken(String)}
207 	 * @see com.foxinmy.weixin4j.mp.model.OauthToken
208 	 * @see com.foxinmy.weixin4j.mp.model.User
209 	 */
210 	public User getAuthorizationUser(String oauthToken, String openid, Lang lang)
211 			throws WeixinException {
212 		String user_info_uri = getRequestUri("sns_user_info_uri");
213 		WeixinResponse response = weixinExecutor.get(String.format(
214 				user_info_uri, oauthToken, openid, lang.name()));
215 
216 		return response.getAsObject(new TypeReference<User>() {
217 		});
218 	}
219 
220 	/**
221 	 * 微信开放平台oauth授权(扫码登陆)<li>
222 	 * redirectUri默认填写weixin4j.properties#open.user.oauth.redirect.uri <li>
223 	 * state默认填写state
224 	 *
225 	 * @see {@link #getOpenAuthorizationURL(String, String)}
226 	 * @return 请求授权的URL
227 	 */
228 	public String getOpenAuthorizationURL() {
229 		String redirectUri = Weixin4jConfigUtil
230 				.getValue("open.user.oauth.redirect.uri");
231 		return getOpenAuthorizationURL(redirectUri, "state");
232 	}
233 
234 	/**
235 	 * 微信开放平台oauth授权(扫码登陆):请求CODE
236 	 *
237 	 * @param redirectUri
238 	 *            重定向地址 域名与审核时填写的授权域名一致
239 	 * @param state
240 	 *            用于保持请求和回调的状态,授权请求后原样带回给第三方
241 	 * @return 请求授权的URL
242 	 * @see <a
243 	 *      href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN">网站扫描登陆oauth授权</a>
244 	 * @see #getAuthorizationToken(String)
245 	 */
246 	public String getOpenAuthorizationURL(String redirectUri, String state) {
247 		String open_user_auth_uri = getRequestUri("open_user_auth_uri");
248 		try {
249 			return String.format(open_user_auth_uri, account.getId(),
250 					URLEncoder.encode(redirectUri, Consts.UTF_8.name()),
251 					"snsapi_login", state);
252 		} catch (UnsupportedEncodingException e) {
253 			;
254 		}
255 		return "";
256 	}
257 }