1. 程式人生 > >微信公眾號開發002-微信網頁授權

微信公眾號開發002-微信網頁授權

閱讀完的我們就知道在獲取使用者授權資訊的時候需要設定回撥域名:

(1)、在微信公眾號請求使用者網頁授權之前,開發者需要先到公眾平臺官網中的“開發 - 介面許可權 - 網頁服務 - 網頁帳號 - 網頁授權獲取使用者基本資訊”的配置選項中,修改授權回撥域名。請注意,這裡填寫的是域名(是一個字串),而不是URL,因此請勿加 http:// 等協議頭;

(3)、如果公眾號登入授權給了第三方開發者來進行管理,則不必做任何設定,由第三方代替公眾號實現網頁授權即可

設定域名:


接下來在功能設定內找到回撥域名設定


在設定裡面有詳細的設定規則(在設定回撥域名時,域名的服務協議不用帶比如百度來說他的域名時http://baidu.com設定的時候只需設定baidu.com就行,回撥域名是我們請求微信介面微信會將相應資訊回饋給我們設定的這個域名下的方法)


2.設定完域名我們開始後端的實現:(下面就以我自己專案中的實現為例作一簡單說明)

首先我們需要知道獲取網頁授權的三種方式:

(1)、以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的使用者的openid的,並且是靜默授權並自動跳轉到回撥頁的。使用者感知的就是直接進入了回撥頁(往往是業務頁面)

(2)、以snsapi_userinfo為scope發起的網頁授權,是用來獲取使用者的基本資訊的。但這種授權需要使用者手動同意,並且由於使用者同意過,所以無須關注,就可在授權後獲取該使用者的基本資訊。

(3)、使用者管理類介面中的“獲取使用者基本資訊介面”,是在使用者和公眾號產生訊息互動或關注後事件推送後,才能根據使用者OpenID來獲取使用者基本資訊。這個介面,包括其他微信介面,都是需要該使用者(即openid)關注了公眾號後,才能呼叫成功的。

在使用者訪問我的公眾號時我設定了引導頁也就是歡迎頁面(廣告頁),當訪問這個頁面時我去請求微信獲取code

	private static Logger log = LoggerFactory.getLogger(SilentAuthorizationController.class);
	//請求微信獲取code 的url
	private static final String OAUTH="https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";          
	@RequestMapping("/index")
	public void getSilentAuthorization(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException{
	log.info("進入授權頁面");
	String state=req.getParameter("uid");
	String url=OAuthService.getOauthUrl(WechatGlobalConfig.REDIRECT_URI,"UTF-8","snsapi_base");		            res.sendRedirect(url);
}	
    其中“WechatGlobalConfig.REDIRECT_URI”為我回調url,微信會將它的返回資訊傳送到我這個方法,

	@RequestMapping("/wechatBack")
	public ModelAndView regainOpenIdBack(HttpServletRequest req,HttpServletResponse res){
		String str="";
		try {
			AccessTokenOAuth accessTokenOAuth=new AccessTokenOAuth();
			//第二步:通過code換取網頁授權access_token
			accessTokenOAuth=OAuthService.getOAuthAccessToken(req.getParameter("code"))
			if(accessTokenOAuth!=null){
				str=accessTokenOAuth.getOpenid();
				log.info("線下支付獲取openId成功:"+str);
			}else{
				log.info("線下支付獲取accessTokenOAuth失敗");
			}   
		} catch (Exception e) {
			// TODO: handle exception
			CreateExceptionMessage.getMessage(e);
			log.error("重新獲取使用者openId進入異常:"+e);
		}	
		ModelAndView m=new ModelAndView("redirect:/wechat/index.html");//跳到公眾號首頁
		m.addObject("openId", str);
		return m;
	}
通過以下三個引數和grant_type(authorization_code)這四個引數換取openId
appid	公眾號的唯一標識
secret	公眾號的appsecret
code	填寫第一步獲取的code引數
package com.deshangshidai.wechat.subscribe.servlet;


import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
import com.deshangshidai.exceptions.CreateExceptionMessage;
import com.deshangshidai.utils.MapUtils;
import com.deshangshidai.wechat.subscribe.token.AccessTokenOAuth;
import com.deshangshidai.wechat.subscribe.util.HttpUtils;
import com.deshangshidai.wechat.subscribe.util.WechatGlobalConfig;
import net.sf.json.JSONObject;

public class OAuthService {
	public static Logger log = Logger.getLogger(OAuthService.class);
	/**
	 * 網頁授權第一步wechat oauth url 
	 */
	public static String OAUTH = WechatGlobalConfig.OAUTH;
	/**
	 * 獲取oauth網頁認證的token
	 */
	public static String GET_ACCESS_TOKEN_OAUTH = WechatGlobalConfig.GET_ACCESS_TOKEN_OAUTH;
	/**
	 * 時間格式化工具
	 */
	private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	/**
	 * 獲得Code的URL
	 * @param redirectUrl 跳轉的url
	 * @param charset 字符集格式
	 * @param scope OAUTH scope
	 * @return oauth url
	 */
	public static String getOauthUrl(String redirectUrl, String charset, String scope) {
		String url = "";
			try {
				url = OAUTH.replace("APPID", WechatGlobalConfig.APP_ID).replace("REDIRECT_URI", URLEncoder.encode(redirectUrl, charset)).replace("SCOPE", scope);
			log.info("獲取驗證token"+url);
			} catch (UnsupportedEncodingException e) {
	        log.error("獲取驗證tokenurl失敗:"+e);
			CreateExceptionMessage.getMessage(e);
			return "500.html";
			}
		return url;
	}


	
	/**
	 *通過code 獲取Access_Token(oAuth認證,此access_token與基礎支援的access_token不同)
	 * 
	 * @param code 使用者授權後得到的code
	 * @return AccessTokenOAuth物件
	 */
	public static AccessTokenOAuth getOAuthAccessToken(String code) {
		log.info("進入code方法獲取使用者資訊");
		AccessTokenOAuth accessTokenOAuth = null;
		long currentTime = System.currentTimeMillis();
		StringBuilder info = new StringBuilder("當前時間:").append(format.format(new Date(currentTime)));
		String url = GET_ACCESS_TOKEN_OAUTH.replace("APPID", WechatGlobalConfig.APP_ID).replace("SECRET", WechatGlobalConfig.APP_SECREAT).replace("CODE", code);
		JSONObject jsonObject = HttpUtils.httpRequest(url, "POST", null);
		if (null != jsonObject) {
			if(!MapUtils.jsonIsAnyBlank(jsonObject, "errcode")){
				info.append("獲取access_token失敗...\nerrcode:" + jsonObject.getInt("errcode") + ",errmsg:" + jsonObject.getString("errmsg"));
			}else {
			log.info("將獲取到的資訊存入accessTokenOAuth物件");
			log.info("openid的值"+jsonObject.getString("openid"));
			accessTokenOAuth = new AccessTokenOAuth();
			accessTokenOAuth.setAccessToken(jsonObject.getString("access_token");
			accessTokenOAuth.setExpiresIn(jsonObject.getInt("expires_in"));
			accessTokenOAuth.setRefreshToken(jsonObject.getString("refresh_token"));
			accessTokenOAuth.setOpenid(jsonObject.getString("openid"));
			accessTokenOAuth.setScope(jsonObject.getString("scope"));
			}
		}else{
			log.info("jsonObject為空");
		}
		log.info(info);
		info = null;
		return accessTokenOAuth;
	}
}
accessTokenOAuth實體類

package com.deshangshidai.wechat.subscribe.token;

/**
 * 網頁授權介面呼叫憑證 OAuth2.0
 * @author txw
 * @version 1.0
 */
public class AccessTokenOAuth {
	/**
	 * 網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
	 */
	private String accessToken;
	
	/**
	 * access_token介面呼叫憑證超時時間,單位(秒)
	 */
	private int expiresIn;
	
	/**
	 * 使用者重新整理access_token
	 */
	private String refreshToken;
	
	/**
	 * 使用者唯一標識,請注意,在未關注公眾號時,使用者訪問公眾號的網頁,也會產生一個使用者和公眾號唯一的OpenID
	 */
	private String openid;
	
	/**
	 * 使用者授權的作用域,使用逗號(,)分隔
	 */
	private String 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 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 AccessTokenOAuth(String accessToken, int expiresIn, String refreshToken, String openid, String scope) {
		super();
		this.accessToken = accessToken;
		this.expiresIn = expiresIn;
		this.refreshToken = refreshToken;
		this.openid = openid;
		this.scope = scope;
	}

	public AccessTokenOAuth() {
		super();
	}

	@Override
	public String toString() {
		return "AccessTokenOAuth [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", refreshToken=" + refreshToken + ", openid=" + openid
				+ ", scope=" + scope +"]";
	}
	
}

第三步:重新整理access_token(如果需要)

由於access_token擁有較短的有效期,當access_token超時後,可以使用refresh_token進行重新整理,refresh_token有效期為30天,當refresh_token失效之後,需要使用者重新授權。

請求方法

獲取第二步的refresh_token後,請求以下連結獲取access_token:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
引數	是否必須	說明
appid	是	公眾號的唯一標識
grant_type	是	填寫為refresh_token
refresh_token	是	填寫通過access_token獲取到的refresh_token引數
返回說明

正確時返回的JSON資料包如下:

{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
引數	描述
access_token	網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
expires_in	access_token介面呼叫憑證超時時間,單位(秒)
refresh_token	使用者重新整理access_token
openid	使用者唯一標識
scope	使用者授權的作用域,使用逗號(,)分隔
錯誤時微信會返回JSON資料包如下(示例為code無效錯誤):

{"errcode":40029,"errmsg":"invalid code"}

第四步:拉取使用者資訊(需scope為 snsapi_userinfo)

如果網頁授權作用域為snsapi_userinfo,則此時開發者可以通過access_token和openid拉取使用者資訊了。

請求方法

http:GET(請使用https協議) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
引數說明

引數	描述
access_token	網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
openid	使用者的唯一標識
lang	返回國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語
返回說明

正確時返回的JSON資料包如下:

{    "openid":" OPENID",
" nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl":    "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
引數	描述
openid	使用者的唯一標識
nickname	使用者暱稱
sex	使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知
province	使用者個人資料填寫的省份
city	普通使用者個人資料填寫的城市
country	國家,如中國為CN
headimgurl	使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空。若使用者更換頭像,原有頭像URL將失效。
privilege	使用者特權資訊,json 陣列,如微信沃卡使用者為(chinaunicom)
unionid	只有在使用者將公眾號繫結到微信開放平臺帳號後,才會出現該欄位。
錯誤時微信會返回JSON資料包如下(示例為openid無效):

{"errcode":40003,"errmsg":" invalid openid "}

附:檢驗授權憑證(access_token)是否有效

請求方法

http:GET(請使用https協議) https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
引數說明

引數	描述
access_token	網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
openid	使用者的唯一標識
返回說明
正確的JSON返回結果:

{ "errcode":0,"errmsg":"ok"}
錯誤時的JSON返回示例:

{ "errcode":40003,"errmsg":"invalid openid"}