微信公眾號之訂閱號(已認證)實現oauth2授權登入詳細步驟介紹
注意:有朋友說部落格中用的是測試號,請大家注意,希望不要誤導大家。
一: 簡介
通過 微信公眾平臺---->許可權介面 可以得知 微信的訂閱號是沒有授權登入介面的,只有服務號才有該許可權。這點微信公眾平臺在多處反覆強調
最終的事實是:微信訂閱號是可以實現授權登入的!
二:具體實現步驟:
1. 首先在 微信公眾平臺(https://mp.weixin.qq.com/) 【開發】----> 【基本配置】----->【伺服器配置】完成基本的配置資訊
URL: 這裡的地址我寫的是我們HTML5專案的某個Controller或Servlet的地址,例如 http://www.example.com/weixin/checkSignature.do
注意這個CheckSignatureController中是要寫程式碼的,程式碼的業務邏輯是要驗證簽名並返回echostr欄位;還需要注意www.example.com 這個地址必須是外網地址(內網不行的), 因為當你配置完所有的基本資訊時,當提交的時候,微信公眾平臺會回答你剛才填的URL地址即http://www.example.com/weixin/checkSignature.do, 如果你填內網的地址,那麼這個URL調不到,如果簽名驗證不過去,這個基本配置就配置不成功。當你寫好這個CheckSignatureController後,還要將程式碼放到測試環境中去,以便微信公眾平臺可以回撥你這個Controller
@Controller @RequestMapping(value="/weixin") public class CheckSignatureController extends BaseController { private static transient final Logger log = LoggerFactory.getLogger(CheckSignatureController.class); public static String WEIXIN_TOKEN = "Token"; @RequestMapping(value ="checkSignature.do", produces = "application/json; charset=utf-8") @ResponseBody public String checkSignature(HttpServletRequest request) { String echostr = request.getParameter("echostr"); // 隨機字串 if (isSignature(request)) { return echostr; } return null; } // 檢查簽名 public boolean isSignature(HttpServletRequest request) { String signature = request.getParameter("signature"); // 微信加密簽名 String timestamp = request.getParameter("timestamp"); // 時間戳 String nonce = request.getParameter("nonce"); // 隨機數 String[] arr = new String[] {timestamp, nonce, WEIXIN_TOKEN}; Arrays.sort(arr); String s = arr[0] + arr[1] + arr[2]; MessageDigest md; byte[] digest = null; try { md = MessageDigest.getInstance("SHA-1"); digest = md.digest(s.getBytes("utf-8")); } catch (Exception e) { e.printStackTrace(); } String sign = bytesToHexString(digest); return signature.equals(sign); } public static final String bytesToHexString(byte[] bArray) { StringBuffer sb = new StringBuffer(bArray.length); String sTemp; for (int i = 0; i < bArray.length; i++) { sTemp = Integer.toHexString(0xFF & bArray[i]); if (sTemp.length() < 2) sb.append(0); sb.append(sTemp.toUpperCase()); } return sb.toString().toLowerCase(); } }
當你點選基本資訊的【提交】按鈕時,微信公眾平臺會向你專案傳送http請求:
http://www.example.com/weixin/checkSignature.do?signature=d96625be6855baa013e6c66cb9155dd38ed8deb5&echostr=8312595572152199567×tamp=1460511115&nonce=534926942
如果這個地址能返回http請求中的echostr引數,就能提交成功,否則提交還會提示報錯
Token:是一個字串,自己隨意寫,但是要保證一點CheckSignatureController中會用到Token這個值,兩者要保證完全一致即可
EncodingAESKey: 我選擇的是隨機生成的
2: 測試號管理
登入這個地址,進行配置:http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
在這個地址中要配置完所有資訊
介面配置資訊
URL: http://www.example.com/weixin/checkSignature.do 和基本資訊配置一樣
Token:和基本配置中的token保持一致
JS介面安全域名
域名:http://www.example.com
體驗介面許可權表
點選修改,然後 填入: www.example.com , 注意不要帶http
三:配置自動回覆
填入:<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=微信開放平臺(網站應用)AppID&redirect_uri=http://www.example.com/oauth2.do&response_type=code&scope=snsapi_login&state=1#wechat_redirect">點選這裡立即體驗</a>
然後儲存
注意:href裡面的值大部分是固定的,特別注意appid引數,如果這個值錯了,你就不能完成授權登入
appid:為微信開放平臺(網站應用,一定要是是網站應用,不能是移動應用)中的AppID(https://open.weixin.qq.com 這個地址中的appid),更不要寫微信公眾平臺中的AppID
scope:引數值為snsapi_login,不要寫snsapi_base和snsapi_userinfo
redirect_uri:這個值寫HTML5專案中的一個Controller的對映地址,當用戶點選立即體驗超連結的時候,會跳轉到授權登入頁面,當點選授權登入之後微信公眾平臺會回撥這個地址,並在這個地址上追加code和state引數值
http://www.example.com/oauth2.do?code=0419p3Cc0YxTtG1nadCc0Ms7Cc09p3C8&state=1
你需要獲取code引數,從而呼叫微信公眾平臺的其他API,進而拿到微信使用者的基本資訊,如暱稱,頭像,性別等
這兩個引數非常關鍵,我在開發中就因為這兩個值沒寫對,卡了好長時間
http://www.example.com/oauth2.do 程式碼邏輯
1. 微信公眾平臺回撥你的地址:http://www.example.com/oauth2.do?code=0419p3Cc0YxTtG1nadCc0Ms7Cc09p3C8&state=1
2. 獲取code引數,呼叫微信公眾平臺access_token介面,來獲取access_token值
3.根據上步獲取的access_token值,呼叫userinfo介面來獲取使用者的基本資訊
具體程式碼如下:
@Controller
public class Oauth2Controller extends BaseController {
private static transient final Logger log = LoggerFactory.getLogger(Oauth2Controller.class);
static String AppID = "微信開放平臺的網站應用(不能是移動應用)https://open.weixin.qq.com (更不是公眾平臺切記)AppID";
static String AppSecret = "微信開放平臺Secret";
static String State = "1";
@RequestMapping(value ="/oauth2.do", produces = "application/json; charset=utf-8")
@ResponseBody
public String mp(HttpServletRequest request) {
// 1. 獲取code ----------------------------------------------------
String CODE = request.getParameter("code");
String state = request.getParameter("state");
if (!State.equals(state)) {
return null;
}
JsonMapper json = JsonMapper.nonDefaultMapper();
AccessTokenHelper accessTokenHelper = AccessTokenHelper.getInstance();
AccessToken accessToken = accessTokenHelper.getAccessToken();
if (accessToken != null) {
Date expireEndDate = accessTokenHelper.getExpireInDate();
if (new Date().getTime() >= expireEndDate.getTime() ) {
// 2.accessToken過期了,需要重新獲取 使用code換取access_token--------
accessToken = requestAccessToken(CODE, json);
}
} else {
accessToken = requestAccessToken(CODE, json);
}
String accessTokenStr = accessToken.getAccess_token();
String openid = accessToken.getOpenid();
log.info("--accessToken: " + accessToken);
// 3.使用access_token獲取使用者資訊-------------------------------
// https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
Map<String, Object> paramMap = new HashMap<String, Object>();
String userinfoURL = "https://api.weixin.qq.com/sns/userinfo";
paramMap.clear();
paramMap.put("access_token", accessTokenStr);
paramMap.put("openid", openid);
String userinfoResponse = HttpClientUtil.doPostSSL(userinfoURL, paramMap);
UserInfo userinfo = json.fromJson(userinfoResponse, UserInfo.class);
log.info("--userinfo: " + userinfo);
return CODE;
}
// https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
public AccessToken requestAccessToken(String code, JsonMapper json) {
String accessTokenURL = "https://api.weixin.qq.com/sns/oauth2/access_token";
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("appid", AppID);
paramMap.put("secret", AppSecret);
paramMap.put("code", code);
paramMap.put("grant_type", "authorization_code");
String accessTokenResponse = HttpClientUtil.doPostSSL(accessTokenURL, paramMap);
AccessToken accessToken = json.fromJson(accessTokenResponse, AccessToken.class);
AccessTokenHelper accessTokenHelper = AccessTokenHelper.getInstance();
int expiresIn = accessToken.getExpires_in();
Date expireEndDate = DateUtil.addSeconds(new Date(), expiresIn);
accessTokenHelper.setExpireInDate(expireEndDate);
accessTokenHelper.setAccessToken(accessToken);
return accessToken;
}
}
該程式碼用到json.fromJson()用於將json資料轉為實體類,大家可以將該方法替換成自己的方法
HttpClientUtil.doPostSSL():是用於傳送https請求的方法,大家可以將該方法替換成自己的方法
整篇文章一直在強調要AppID使用微信開放平臺的網站應用AppID,
微信開放平臺:登入:https://open.weixin.qq.com ---》 管理中心------》網站應用 如果你還沒有網站應用那就必須建立一個網站應用,提交稽核好像是要收費300元的
當Oauth2Controller開發後,放到測試環境中,此時要注意測試環境的伺服器的JDK,不能使用OpenJDK,要使用Sun的SDK,否則在傳送https請求會報錯。
注意:有的評論說這篇部落格幫助了他,有的說部落格內容有誤,我也不是很清楚,我只是把我在公司做的這個功能記錄上來,上線也一直在用,具體部落格內容有沒有問題請大家自己判斷,畢竟不是所有的部落格都100%的對,本人水平有限