微信開發五: 網頁授權
阿新 • • 發佈:2019-01-08
微信開發文件:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
構造到授權的網頁連結
使用方式:例
// new baseservice().BuildAuthCallbackUrl("/mydemo/product/ProductDetails?id="+product.getId(), EnumScopeType.snsapi_userinfo);
package com.star.wxservice; import java.io.IOException; import java.io.UnsupportedEncodingException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.star.etmvcfilters.BaseServcie; import com.star.model.UserSessionUtil; import com.star.model.Wechat_User; import com.star.utils.Cache; import com.star.utils.CacheManager; import com.star.utils.HttpRequestUtil; import com.star.utils.JsonMapper; import com.star.wxmessagemodel.EnumScopeType; import com.star.wxmessagemodel.OpenIdResult; import com.star.wxmessagemodel.RefreshtokenResult; import com.star.wxmessagemodel.TokenJsonResult; import com.star.wxmessagemodel.WechatUserInfo; import config.Property; public class baseservice { private static Logger logger = Logger.getLogger(baseservice.class); private static final String WECHAR_PATH = "/config/wechat.properties"; public static final String WECHAT_APPID = Property.GetXMLValuesByKey(WECHAR_PATH, "WECHAT_APPID"); public static final String WECHAT_SECRET = Property.GetXMLValuesByKey(WECHAR_PATH, "WECHAT_SECRET"); private static final String Web_PATH = "/config/web.properties"; /** * 當前域名 */ public static String ServerName = Property.GetXMLValuesByKey(Web_PATH, "ServerName"); /** * 獲取每次操作微信API的Token訪問令牌 * * @return <param name="appid">應用ID</param> * <param name="secret">開發者憑據</param> * @throws Exception */ public String GetAccessToken() throws Exception { String key = "weixin.accesstoken"; // 正常情況下access_token有效期為7200秒,這裡使用快取設定短於這個時間即可 String token = ""; if (CacheManager.getCacheInfo(key) == null) { String grant_type = "client_credential"; String url = "https://api.weixin.qq.com/cgi-bin/token"; String para = String.format("grant_type=%s&appid=%s&secret=%s", grant_type, WECHAT_APPID, WECHAT_SECRET); String jsonStr = HttpRequestUtil.sendGet(url, para); TokenJsonResult jsonObject = JsonMapper.json2Bean(jsonStr, TokenJsonResult.class); Cache cache = new Cache(); cache.setKey("accesstoken"); cache.setValue(jsonObject.getAccess_token()); cache.setTimeOut(7000); cache.setExpired(false); CacheManager.putCache(key, cache); return jsonObject.getAccess_token(); } else { return CacheManager.getCacheInfo(key).getValue().toString(); } } /** * 獲取openId * * @param code * @return * @throws Exception */ public OpenIdResult GetOpenId(String code) throws Exception { String url = "https://api.weixin.qq.com/sns/oauth2/access_token"; String para = String.format("appid=%s&secret=%s&code=%s&grant_type=authorization_code", WECHAT_APPID, WECHAT_SECRET, code); String jsonStr = HttpRequestUtil.sendGet(url, para); OpenIdResult result = JsonMapper.json2Bean(jsonStr, OpenIdResult.class); return result; } /** * 獲取微信使用者基本資訊 -靜默授權 * * @param openId * @return * @throws Exception */ public WechatUserInfo GetUserInfo(String openId) throws Exception { logger.error("OPENID=============================================" + openId); String url = "https://api.weixin.qq.com/cgi-bin/user/info"; String para = String.format("access_token=%s&openid=%s&lang=zh_CN", GetAccessToken(), openId); String jsonStr = HttpRequestUtil.sendGet(url, para); // jsonStr = new String(jsonStr.getBytes("ISO-8859-1"), "UTF-8"); logger.error("OPENID---jsonStr =============================================" + jsonStr); WechatUserInfo model = JsonMapper.json2Bean(jsonStr, WechatUserInfo.class); return model; } /// <summary> /// 構造URL /// </summary> /// <param name="pathAndQuery"></param> /// <returns></returns> public String GetUrl(String pathAndQuery) { return String.format("%s%s", ServerName, pathAndQuery);// pathAndQuery.TrimStart('/') } /** * 構造微信通用授權URL * * @param redirectUrl * 授權後跳轉的頁面 * @param state * 自定義函式 * @param scope * 授權型別 :snsapi_base 靜默授權, snsapi_userinfo手動同意授權 * @return */ public String BuildAuthUrl(String redirectUrl, String state, String scope) { String apiUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; try { redirectUrl = java.net.URLEncoder.encode(redirectUrl, "utf-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return String.format(apiUrl, WECHAT_APPID, redirectUrl, scope, state); } /** * 構造授權回撥地址 * * @param type * 頁面型別 * @param scope * 授權型別 :snsapi_base 靜默授權, snsapi_userinfo手動同意授權 * @return */ public String BuildAuthCallbackUrl(String returnUrl, EnumScopeType scope) { String url = BuildAuthUrl(GetUrl(String.format("/yeewii.m/WXApi/Auth?action=%s", returnUrl)), "state", scope.toString());// Guid.NewGuid().ToString().Replace("-", System.out.println("============================="); // "") // // System.out.println(url); // "") return url; } /// <summary> /// 登入,若使用者存在,則返回登入後的使用者資訊,否則返回null /// </summary> /// <param name="openId"></param> /// <returns></returns> public Wechat_User LoginInternal(HttpServletRequest request, HttpServletResponse response, String openId, WechatUserInfo wxUser) throws Exception { UserSessionUtil session = new UserSessionUtil(); session.setHeadimgurl(wxUser != null ? wxUser.headimgurl : ""); session.setNickname(wxUser != null ? wxUser.nickname : ""); session.setOpenId(wxUser != null ? wxUser.openid : ""); request.getSession().setAttribute("wxUser", session); Wechat_User webchatuser = Wechat_User.findFirst(Wechat_User.class, "openid=?", new Object[] { openId }); if (webchatuser != null) { BaseServcie.sendAutoLoginCookie(request, response, webchatuser); } return webchatuser; } /** * 重新整理access_token(如果需要) * * @param refresh_token * @return * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public RefreshtokenResult Refreshtoken(String refresh_token) throws JsonParseException, JsonMappingException, IOException { String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; String para = String.format("appid=%s&grant_type=refresh_token&refresh_token=%s", WECHAT_APPID, refresh_token); String jsonStr = HttpRequestUtil.sendGet(url, para); RefreshtokenResult result = JsonMapper.json2Bean(jsonStr, RefreshtokenResult.class); return result; } /** * 獲取微信使用者基本資訊 -手動授權 * * @param openId * @param accessToken * @param refresh_token * @return * @throws Exception * @throws JsonMappingException * @throws IOException */ public WechatUserInfo GetSnsapiUserinfo(String openId, String accessToken, String refresh_token) throws Exception, JsonMappingException, IOException { String url = "https://api.weixin.qq.com/sns/userinfo"; RefreshtokenResult toRefreshtokenResult = Refreshtoken(refresh_token); String para = String.format("access_token=%s&openid=%s&lang=zh_CN", accessToken, openId); String jsonStr = HttpRequestUtil.sendGet(url, para); WechatUserInfo result = JsonMapper.json2Bean(jsonStr, WechatUserInfo.class); return result; // 在獲取使用者資訊時,提示,"errcode": 48001, 介面未被授權 // 需要使用者提升為服務號,並且進行認證繳交每年300元 } /** * 最底層字串編碼轉換的實現方法 * * @param str * 待轉換的字串 * @param oldCharset * 源字符集 * @param newCharset * 目標字符集 * @return 轉換後的字串 */ public String changeCharset(String str, String oldCharset, String newCharset) { if (str != null) { // 用源字元編碼解碼字串 try { return new String(str.getBytes(oldCharset), newCharset); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return null; } }
相關轉換實體類
package com.star.wxmessagemodel;
public enum EnumScopeType {
/**
* 靜默授權
*/
snsapi_base,
/**
* 需手動同意授權
*/
snsapi_userinfo,
}
package com.star.wxmessagemodel; public class OpenIdResult { public String access_token; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public String getExpires_in() { return expires_in; } public void setExpires_in(String expires_in) { this.expires_in = expires_in; } 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; } public String getErrcode() { return errcode; } public void setErrcode(String errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } public String expires_in; public String refresh_token; public String openid; public String scope; public String errcode; public String errmsg; public String unionid; public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } }
package com.star.wxmessagemodel; /** * 重新整理access_token(如果需要) * 由於access_token擁有較短的有效期,當access_token超時後,可以使用refresh_token進行重新整理,refresh_token擁有較長的有效期(7天、30天、60天、90天),當refresh_token失效的後,需要使用者重新授權。 * * @author Administrator * */ public class RefreshtokenResult { public String access_token; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public String getExpires_in() { return expires_in; } public void setExpires_in(String expires_in) { this.expires_in = expires_in; } 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; } public String expires_in; public String refresh_token; public String openid; public String scope; }
package com.star.wxmessagemodel;
public class TicketResult {
public String errcode;
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
public String errmsg;
public String ticket;
public String expires_in;
}
package com.star.wxmessagemodel;
public class TokenJsonResult {
public String access_token;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String expires_in;
public String errcode;
public String errmsg;
}
cache
package com.star.utils;
public class Cache {
private String key;// 快取ID
private Object value;// 快取資料
private long timeOut;// 更新時間
private boolean expired; // 是否終止
public Cache() {
super();
}
public Cache(String key, Object value, long timeOut, boolean expired) {
this.key = key;
this.value = value;
this.timeOut = timeOut;
this.expired = expired;
}
public String getKey() {
return key;
}
public long getTimeOut() {
return timeOut;
}
public Object getValue() {
return value;
}
public void setKey(String string) {
key = string;
}
public void setTimeOut(long l) {
timeOut = l;
}
public void setValue(Object object) {
value = object;
}
public boolean isExpired() {
return expired;
}
public void setExpired(boolean b) {
expired = b;
}
}
回撥地址 (獲取使用者資訊) 返回到指定頁面
/**
* 回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面
*
* @param code
* @param state
* @return
* @throws Exception
*/
public JspView Auth(String code, String state) throws Exception {
String targetUrl = "";
Wechat_User user = new Wechat_User();
String openId = "";
try {
targetUrl = request.getParameter("action");
// String actionValue = request.getParameter("action");
// // 也可以這樣判斷 是否在其中
// //
// Arrays.asList(EnumWechatMenuType.values()).contains(actionValue);
// if (!EnumWechatMenuType.IsIndexfoNo(actionValue)) {
// // String.format("微信授權回撥錯誤,未知的動作:{0}.", actionValue)
// }
baseservice baseService = new baseservice();
OpenIdResult openresult = baseService.GetOpenId(code);
openId = openresult.getOpenid();
String accessToken = openresult.getAccess_token();
String refresh_token = openresult.getRefresh_token();
// WechatUserInfo wxUser = baseService.GetUserInfo(openId);//
// //
// 以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的使用者的openid的,並且是靜默授權並自動跳轉到回撥頁的。使用者感知的就是直接進入了回撥頁(往往是業務頁面)
WechatUserInfo wxUser = baseService.GetSnsapiUserinfo(openId, accessToken, refresh_token);
//
// 以snsapi_userinfo為scope發起的網頁授權,是用來獲取使用者的基本資訊的。但這種授權需要使用者手動同意,並且由於使用者同意過,所以無須關注,就可在授權後獲取該使用者的基本資訊。
user = baseService.LoginInternal(request, response, openId, wxUser);
// for (EnumWechatMenuType name : EnumWechatMenuType.values()) {
// if (name.toString().equals(actionValue)) {
// targetUrl = name.getReturnurl();
// break;
// }
// }
if (user == null) {
Map<String, Object> map = new Wechat_UserDao().do_Wechatreg(request, response, openId, wxUser.nickname,
wxUser.headimgurl, "", "");
if (!map.get("result").equals(true) && !map.get("result").equals("true")) {
// 做失敗操作
logger.error("回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面==獲取使用者資訊失敗");
}
}
} catch (Exception ex) {
// 異常操作
logger.error("回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面==獲取使用者資訊異常" + ex);
}
redirect(targetUrl);
JspView view = new JspView(targetUrl);
view.setAttribute("user", user);
return view;
}