四、通过code换取网页授权access_token
这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。
请求参数封装
package com.phil.wechatauth.model.req;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import com.phil.common.params.AbstractParams;
/**
* 获取授权请求token的请求参数
* @author phil
* @date 2017年7月2日
*
*/
public class AuthTokenParams extends AbstractParams implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4652953400751046159L;
private String appid; //公众号的唯一标识
private String secret; //公众号的appsecret
private String code; //填写第一步获取的code参数
private String grant_type = "authorization_code";
public AuthTokenParams() {
super();
}
public AuthTokenParams(String appid, String secret, String code, String grant_type) {
super();
this.appid = appid;
this.secret = secret;
this.code = code;
this.grant_type = grant_type;
}
/**
* 参数组装
* @return
*/
public Map getParams() {
Map params = new TreeMap();
params.put("appid", this.appid);
params.put("secret", this.secret);
params.put("code", this.code);
params.put("grant_type", this.grant_type);
return params;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getGrant_type() {
return grant_type;
}
}
返回的json封装
package com.phil.wechatauth.model.resp;
/**
* 网页授权access_token
*
* @author phil
* @date 2017年7月2日
*
*/
public class AuthAccessToken extends AccessToken {
private String refresh_token; // 用户刷新access_token
private String openid; // 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
private String scope; // 用户授权的作用域,使用逗号(,)分隔
public String getRefresh_token() {
return refresh_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
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;
}
}
获取access_token方法
/**
* 获取网页授权凭证
* @param basic
* @param path
* @return
*/
public AuthAccessToken getAuthAccessToken(AbstractParams basic, String path) {
AuthAccessToken authAccessToken = null;
//获取网页授权凭证
try {
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, path, basic.getParams(), null);
if(result != null){
authAccessToken = JsonUtil.fromJson(result, AuthAccessToken.class);
}
} catch (Exception e) {
authAccessToken = null;
logger.info("error"+e.getMessage());
}
return authAccessToken;
}
获取授权进入页面
// 获取token的链接
private final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
@RequestMapping(value = "bindWxPhone", method = { RequestMethod.GET })
public String prize(HttpServletRequest request, HttpServletResponse response, String url) throws Exception {
AuthAccessToken authAccessToken = null;
// 用户同意授权后可以获得code,检验state
String code = request.getParameter("code");
if(code==null){
return null;
}
String state = request.getParameter("state");
if(state.equals(MD5Util.MD5Encode("ceshi", ""))){
AuthTokenParams authTokenParams = new AuthTokenParams();
authTokenParams.setAppid("");
authTokenParams.setSecret("");
authTokenParams.setCode(code);
authAccessToken = oAuthService.getAuthAccessToken(authTokenParams, ACCESS_TOKEN_URL);
}
if(authAccessToken!=null){
logger.info("网页授权的accessToken=" + authAccessToken.getAccess_token());
logger.info("正在绑定的openid=" + authAccessToken.getOpenid());
}
return "/system/wxuserprize/bindPhone";
}
五、刷新access_token(如果需要)
由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。
请求参数封装
package com.phil.wechatauth.model.req;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import com.phil.common.params.AbstractParams;
/**
* 刷新token请求
* @author phil
* @date 2017年7月2日
*
*/
public class RefreshTokenParams extends AbstractParams implements Serializable{
/**
*
*/
private static final long serialVersionUID = -7200815808171378571L;
private String appid;
private String grant_type = "refresh_token";
private String refresh_token;
public RefreshTokenParams(String appid, String grant_type, String refresh_token) {
super();
this.appid = appid;
this.grant_type = grant_type;
this.refresh_token = refresh_token;
}
/**
* 参数组装
*
* @return
*/
public Map getParams() {
Map params = new TreeMap();
params.put("appid", this.appid);
params.put("grant_type", this.grant_type);
params.put("refresh_token", this.refresh_token);
return params;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getGrant_type() {
return grant_type;
}
public String getRefresh_token() {
return refresh_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
}
/**
* 刷新网页授权验证
* @param basic 参数
* @param path 请求路径
* @return
*/
public String refreshAuthAccessToken(AbstractParams basic, String path) {
AuthAccessToken authAccessToken = null;
//刷新网页授权凭证
try {
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, path, basic.getParams(), null);
if(result != null){
authAccessToken = JsonUtil.fromJson(result, AuthAccessToken.class);
}
} catch (Exception e) {
authAccessToken = null;
logger.info("error"+e.getMessage());
}
return authAccessToken==null?null:authAccessToken.getAccess_token();
}
六、拉取用户信息
如果网页授权作用域为snsapi_userinfo,则此时可以通过access_token和openid拉取用户信息了
通过网页授权获取的用户信息
/**
* 通过网页授权获取的用户信息
*
* @author phil
*/
public class AuthUserInfo {
// 用户标识
private String openid;
// 用户昵称
private String nickname;
// 性别(1是男性,2是女性,0是未知)
private String sex;
// 国家
private String country;
// 省份
private String province;
// 城市
private String city;
// 用户头像链接
private String headimgurl;
// 用户特权信息
private List privilege;
// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
private String unionid;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public List getPrivilege() {
return privilege;
}
public void setPrivilege(List privilege) {
this.privilege = privilege;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
}
获取方法
//获取授权用户信息
private final String USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
/**
* 通过网页授权获取用户信息
* @param accessToken
* @param openid
* @return
*/
public AuthUserInfo getAuthUserInfo(String accessToken, String openid) {
AuthUserInfo authUserInfo = null;
//通过网页授权获取用户信息
Map params = new TreeMap();
params.put("openid", openid);
params.put("access_token", accessToken);
String result = HttpReqUtil.HttpsDefaultExecute(HttpReqtUtil.GET_METHOD, USERINFO_URL, params, null);
if(null != result){
try {
authUserInfo = JsonUtil.fromJson(result, AuthUserInfo.class);
} catch (JsonSyntaxException e) {
logger.info("transfer exception");
}
}
return authUserInfo;
}
七、检验授权凭证(access_token)是否有效
//判断用户accessToken是否有效
private final String AUTH_URL = "https://api.weixin.qq.com/sns/auth";
/**
* 检验授权凭证(access_token)是否有效
* @param accessToken 网页授权接口调用凭证
* @param openid用户的唯一标识
* @return { "errcode":0,"errmsg":"ok"}表示成功 { "errcode":40003,"errmsg":"invalid openid"}失败
*/
public ResultState authToken(String accessToken,String openid){
ResultState state = null;
Map params = new TreeMap();
params.put("access_token",accessToken);
params.put("openid", openid);
String json = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, AUTH_URL, params,"");
if(json!=null){
state = JsonUtil.fromJson(json, ResultState.class);
}
return state;
}