昨天在寫一個手機版的web項目,要在微信客戶端使用微信第三方登錄,想着也沒啥,看看就看看吧,但是可惡的微信官方文檔給我畫了很大的一個坑,特此記錄
二次更新,說明一下我這個是用我微信網頁授權,就是在微信客戶端點開鏈接或菜單能彈出微信授權登錄框的功能!
前期準備工作我就不多說了,無非就是公衆平臺賬號,填寫相關資料耐心等待審覈就好。
這裏要注意一點的是,網站應用創建好之後的授權回調域填寫頂級域名就好,之前我一直寫的二級域名,測試的時候回調總是過不來,後來回來看文檔,微信說的就是,該域名下的所有頁面都 可以回調
創建好網站應用之後我們來看微信提供的接口文檔
第一步:請求CODE
根據官方文檔,請求code這裏要按照響應的參數進行拼接,參數就按照官方提供的,需要注意的是appid是你用哪個公衆號登錄就用哪個公衆號的appid,這裏不是開放平臺的網站應用appid
然後另一個坑,redirect_uri,一定要用urlEncode對鏈接進行處理,這個鏈接是用戶打開這個鏈接同意登錄之後會跳轉的地址,我們要跳轉到後臺對回調的信息就行處理,所以就要回調到我們域名下的controller控制器方法中,並且一定是要外網可訪問。比如:www.test.com/callback
把鏈接進行Encode處理,這裏提供一個 encode在線解碼工具
拼接好路徑之後再微信客戶端打開就應該會顯示某某公衆號的授權登錄頁面了,如果報錯那就是路徑沒有拼接正確
請求code的控制器如下所示:
參數是我自己的,換成你的參數就好
@RequestMapping("/getCode")
public void getCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
//拼接url
StringBuilder url = new StringBuilder();
url.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
//微信開放平臺的appid
url.append("appid=" + WeixinConfig.appId);
//轉碼
try {
//回調地址 ,回調地址要進行Encode轉碼
String redirect_uri = URLEncoder.encode(WeixinConfig.REDIRECT_URI, "utf-8");
System.out.println("redirect_uri==" + redirect_uri);
url.append("&redirect_uri=" + redirect_uri);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
url.append("&response_type=code");
url.append("&scope=snsapi_userinfo");
url.append("&state=" + request.getSession().getId());
url.append("#wechat_redirect");
System.out.println("url===" + url.toString());
// return "redirect:" + url.toString();
String s = url.toString();
response.sendRedirect(s);
}
返回說明
用戶允許授權後,將會重定向到redirect_uri的網址上,並且帶上code和state參數
第二步:通過code換取網頁授權access_token
第三步:刷新access_token(如果需要)
第四步:拉取用戶信息(需scope爲 snsapi_userinfo)
這三步我們應該在上面授權回調方法中調用,起初我在想每一個方法都要返回一個json,那麼是不是我要三個控制器方法纔行?,怎樣才能在一個控制器裏調用三個方法呢?
感謝大神提供的發送GET請求的工具類:
public static JSONObject doGetJson(String url) throws Exception, IOException {
JSONObject jsonObject = null;
//初始化httpClient
DefaultHttpClient client = new DefaultHttpClient();
//用Get方式進行提交
HttpGet httpGet = new HttpGet(url);
//發送請求
HttpResponse response = client.execute(httpGet);
//獲取數據
HttpEntity entity = response.getEntity();
//格式轉換
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
jsonObject = JSONObject.fromObject(result);
}
//釋放鏈接
httpGet.releaseConnection();
return jsonObject;
}
最後附上我的授權回調方法:
/**
* 微信 授權登錄回調
**/
@RequestMapping("/callback")
public void callback(String code, String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("====" + code + "===" + state + "====");
logger.debug("code===" + code);
logger.debug("state===" + state);
if (StringUtils.isNotEmpty(code)) {
logger.debug("sssssssss====" + code);
StringBuilder url = new StringBuilder();
url.append("https://api.weixin.qq.com/sns/oauth2/access_token?");
//微信公衆平臺的AK和SK
url.append("appid=" + WeixinConfig.appId);
url.append("&secret=" + WeixinConfig.appSecret);
//這是微信回調給你的code
url.append("&code=" + code);
url.append("&grant_type=authorization_code");
System.out.println("url.toString()===" + url.toString());
logger.debug("url.toString()===" + url.toString());
JSONObject jsonObject = AuthUtil.doGetJson(url.toString());
logger.debug("jsonObject================"+jsonObject);
//解析jsonStr的字符串
//1.獲取微信用戶的openid
String openid = jsonObject.getString("openid");
//2.獲取獲取access_token
String access_token = jsonObject.getString("access_token");
logger.debug("openid===" + openid);
logger.debug("access_token===" + access_token);
String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid
+ "&lang=zh_CN";
logger.debug("infoUrl===" + infoUrl);
//3.獲取微信用戶信息
JSONObject userInfo = AuthUtil.doGetJson(infoUrl);
logger.debug("userInfo======================"+userInfo);
//至此拿到了微信用戶的所有信息,剩下的就是業務邏輯處理部分了
//保存openid和access_token到session
if (openid==null){
logger.debug("-------------------------微信授權回調,獲取用戶信息失敗!=============================");
response.sendRedirect("http://m.huerdai.net/html/Program-error.html");
return;
}
request.getSession().setAttribute("openid", openid);
request.getSession().setAttribute("access_token", access_token);
logger.debug("openid===" + openid);
logger.debug("access_token===" + access_token);
String sessionid = getRequest().getSession().getId();
//去數據庫查詢有沒有這個 openid
CustomerInfo customerInfoServiceOne = iCustomerInfoService.getOne(new QueryWrapper<CustomerInfo>().eq("openid", openid));
//如果沒有這一個用戶,則創建
if (customerInfoServiceOne == null) {
CustomerInfo customerInfo = new CustomerInfo();
//省略實體set方法
boolean save = registerService.register(customerInfo);
if (save) {
logger.debug("首次認證:http://m.huerdai.net");
redisTemplate.opsForValue().set(sessionid, customerInfoServiceOne.getCustomerId());
// response.sendRedirect("http://m.huerdai.net/index.html");
response.sendRedirect("http://m.huerdai.net/html/bind-tel.html");
return;
} else {
logger.debug("認證失敗!");
response.sendRedirect("http://m.huerdai.net/error.html");
return;
}
} else {
//已經授權過,沒有綁定手機號,也是直接跳轉到首頁
redisTemplate.opsForValue().set(sessionid, customerInfoServiceOne.getCustomerId());
if (customerInfoServiceOne.getMobilePhone() == null) {
logger.debug("已經授權過,沒有綁定手機號,也是直接跳轉到首頁");
//並且將用戶信息存到Redis中
// response.sendRedirect("http://m.huerdai.net/index.html");
response.sendRedirect("http://m.huerdai.net/html/bind-tel.html");
return;
} else {
//已經授權過,並且已經綁定手機號
logger.debug("有openid的跳轉http://m.huerdai.net222222");
response.sendRedirect("http://m.huerdai.net/index.html");
return;
}
}
} else {
logger.debug("code獲取失敗!====" + code);
// return new ModelAndView("redirect:http://m.huerdai.net/error.html");
response.sendRedirect("http://m.huerdai.net/error.html");
}
}
到這裏就微信登錄並且獲取用戶信息就算完成了,
然後我遇到一個問題就是用戶首次登錄進來的時候會報openid找不到異常,第二次進來就好了,也沒有其他報錯信息,期待有大佬路過指正問題原因,感激不盡!
這之間其他的一些問題異常和容易碰到的坑以後有時間再總結!