javascript
Spring Boot 微信-网页授权获取用户信息
微信-驗證服務器有效性
微信-網頁授權獲取用戶信息
網頁授權獲取用戶信息步驟
第一步:用戶同意授權,獲取code
第二步:通過code換取網頁授權access_token
第三步:拉取用戶信息(需scope為 snsapi_userinfo)
第一步:用戶同意授權,獲取code
要填寫網頁授權回調域名:
1.在網頁帳號處點擊”修改”按鈕
2.填寫域名(注意不要http://, 不要后面的路由)
在確保微信公眾賬號擁有授權作用域(scope參數)的權限的前提下(服務號獲得高級接口后,默認擁有scope參數中的snsapi_base和snsapi_userinfo),引導用戶打開如下頁面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect若提示“該鏈接無法訪問”,請檢查參數是否填寫錯誤,是否擁有scope參數對應的授權作用域權限。
參數說明
| appid | 是 | 公眾號的唯一標識 |
| redirect_uri | 是 | 授權后重定向的回調鏈接地址,請使用urlencode對鏈接進行處理 |
| response_type | 是 | 返回類型,請填寫code |
| scope | 是 | 應用授權作用域,snsapi_base (不彈出授權頁面,直接跳轉,只能獲取用戶openid),snsapi_userinfo (彈出授權頁面,可通過openid拿到昵稱、性別、所在地。并且,即使在未關注的情況下,只要用戶授權,也能獲取其信息) |
| state | 否 | 重定向后會帶上state參數,開發者可以填寫a-zA-Z0-9的參數值,最多128字節 |
| wechat_redirect | 是 | 無論直接打開還是做頁面302重定向時候,必須帶此參數 |
如果用戶點擊同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。
若用戶禁止授權,則重定向后不會帶上code參數,僅會帶上state參數redirect_uri?state=STATE
code說明 :
code作為換取access_token的票據,每次用戶授權帶上的code將不一樣,code只能使用一次,5分鐘未被使用自動過期。
第二步:通過code換取網頁授權access_token
首先請注意,這里通過code換取的是一個特殊的網頁授權access_token,與基礎支持中的access_token(該access_token用于調用其他接口)不同。
公眾號可通過下述接口來獲取網頁授權access_token。如果網頁授權的作用域為snsapi_base,則本步驟中獲取到網頁授權access_token的同時,也獲取到了openid,snsapi_base式的網頁授權流程即到此為止。
獲取code后,GET請求以下鏈接獲取access_token:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_codeGET參數說明
| appid | 是 | 公眾號的唯一標識 |
| secret | 是 | 公眾號的appsecret |
| code | 是 | 填寫第一步獲取的code參數 |
| grant_type | 是 | 填寫為authorization_code |
正確時返回的JSON數據包如下:
{"access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE","unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }| access_token | 網頁授權接口調用憑證,注意:此access_token與基礎支持的access_token不同 |
| expires_in | access_token接口調用憑證超時時間,單位(秒) |
| refresh_token | 用戶刷新access_token |
| openid | 用戶唯一標識,請注意,在未關注公眾號時,用戶訪問公眾號的網頁,也會產生一個用戶和公眾號唯一的OpenID |
| scope | 用戶授權的作用域,使用逗號(,)分隔 |
| unionid | 只有在用戶將公眾號綁定到微信開放平臺帳號后,才會出現該字段。 |
錯誤時微信會返回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將失效。 |
錯誤時微信會返回JSON數據包如下(示例為openid無效):
{"errcode":40003,"errmsg":" invalid openid "}終于上代碼了:
HttpsUtil.java
package com.jeiker.demo.util;import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import java.io.*; import java.net.URL;public class HttpsUtil {/*** 以https方式發送請求并將請求響應內容以String方式返回** @param path 請求路徑* @param method 請求方法* @param body 請求數據體* @return 請求響應內容轉換成字符串信息*/public static String httpsRequestToString(String path, String method, String body) {if (path == null || method == null) {return null;}String response = null;InputStream inputStream = null;InputStreamReader inputStreamReader = null;BufferedReader bufferedReader = null;HttpsURLConnection conn = null;try {// 創建SSLConrext對象,并使用我們指定的信任管理器初始化TrustManager[] tm = {new JEEWeiXinX509TrustManager()};SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 從上述對象中的到SSLSocketFactorySSLSocketFactory ssf = sslContext.getSocketFactory();System.out.println(path);URL url = new URL(path);conn = (HttpsURLConnection) url.openConnection();conn.setSSLSocketFactory(ssf);conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);//設置請求方式(git|post)conn.setRequestMethod(method);//有數據提交時if (null != body) {OutputStream outputStream = conn.getOutputStream();outputStream.write(body.getBytes("UTF-8"));outputStream.close();}// 將返回的輸入流轉換成字符串inputStream = conn.getInputStream();inputStreamReader = new InputStreamReader(inputStream, "UTF-8");bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuffer buffer = new StringBuffer();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}response = buffer.toString();} catch (Exception e) {} finally {if (conn != null) {conn.disconnect();}try {bufferedReader.close();inputStreamReader.close();inputStream.close();} catch (IOException execption) {}}return response;} }JEEWeiXinX509TrustManager.java
package com.jeiker.demo.util;import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate;class JEEWeiXinX509TrustManager implements X509TrustManager {public void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType)throws CertificateException {}public X509Certificate[] getAcceptedIssuers() {return null;} }UserInfoUtil.java
package com.jeiker.demo.util;import org.slf4j.Logger; import org.slf4j.LoggerFactory;public class UserInfoUtil {private Logger logger = LoggerFactory.getLogger(getClass());// 1.獲取code的請求地址public static String Get_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STAT#wechat_redirect";// 替換字符串public static String getCode(String APPID, String REDIRECT_URI,String SCOPE) {return String.format(Get_Code,APPID,REDIRECT_URI,SCOPE);}// 2.獲取Web_access_tokenhttps的請求地址public static String Web_access_tokenhttps = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";// 替換字符串public static String getWebAccess(String APPID, String SECRET,String CODE) {return String.format(Web_access_tokenhttps, APPID, SECRET,CODE);}// 3.拉取用戶信息的請求地址public static String User_Message = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";// 替換字符串public static String getUserMessage(String access_token, String openid) {return String.format(User_Message, access_token,openid);}public static void main(String[] args) {String REDIRECT_URI = "http://wechat.tmqyt.com/url";String SCOPE = "snsapi_login"; // snsapi_userinfo // snsapi_login//appIdString appId = "wx222e322a20897ea3";String getCodeUrl = getCode(appId, REDIRECT_URI, SCOPE);System.out.println("getCodeUrl:"+getCodeUrl);} }RedirectController.java
package com.jeiker.demo.controller;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.jeiker.demo.util.HttpsUtil; import com.jeiker.demo.util.UserInfoUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;@RestController public class RedirectController {private Logger logger = LoggerFactory.getLogger(getClass());public static final String WX_APPID = "wx222e322a20897ea3";public static final String WX_APPSECRET = "c9d547819234dd0059bf4b23422409e1";/*** 微信網頁授權流程:* 1. 用戶同意授權,獲取 code* 2. 通過 code 換取網頁授權 access_token* 3. 使用獲取到的 access_token 和 openid 拉取用戶信息* @param code 用戶同意授權后,獲取到的code* @param state 重定向狀態參數* @return*/@GetMapping("/url")public String wecahtLogin(@RequestParam(name = "code", required = false) String code,@RequestParam(name = "state") String state) {// 1. 用戶同意授權,獲取codelogger.info("收到微信重定向跳轉.");logger.info("用戶同意授權,獲取code:{} , state:{}", code, state);// 2. 通過code換取網頁授權access_tokenif (code != null || !(code.equals(""))) {String APPID = WX_APPID;String SECRET = WX_APPSECRET;String CODE = code;String WebAccessToken = "";String openId = "";String nickName,sex,openid = "";String REDIRECT_URI = "http://www.xxx.com/url";String SCOPE = "snsapi_userinfo";String getCodeUrl = UserInfoUtil.getCode(APPID, REDIRECT_URI, SCOPE);logger.info("第一步:用戶授權, get Code URL:{}", getCodeUrl);// 替換字符串,獲得請求access token URLString tokenUrl = UserInfoUtil.getWebAccess(APPID, SECRET, CODE);logger.info("第二步:get Access Token URL:{}", tokenUrl);// 通過https方式請求獲得web_access_tokenString response = HttpsUtil.httpsRequestToString(tokenUrl, "GET", null);JSONObject jsonObject = JSON.parseObject(response);logger.info("請求到的Access Token:{}", jsonObject.toJSONString());// { // "access_token":"ACCESS_TOKEN", // "expires_in":7200, // "refresh_token":"REFRESH_TOKEN", // "openid":"OPENID", // "scope":"SCOPE", // "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" // }if (null != jsonObject) {try {WebAccessToken = jsonObject.getString("access_token");openId = jsonObject.getString("openid");logger.info("獲取access_token成功!");logger.info("WebAccessToken:{} , openId:{}", WebAccessToken, openId);// 3. 使用獲取到的 Access_token 和 openid 拉取用戶信息String userMessageUrl = UserInfoUtil.getUserMessage(WebAccessToken, openId);logger.info("第三步:獲取用戶信息的URL:{}", userMessageUrl);// 通過https方式請求獲得用戶信息響應String userMessageResponse = HttpsUtil.httpsRequestToString(userMessageUrl, "GET", null);JSONObject userMessageJsonObject = JSON.parseObject(userMessageResponse);logger.info("用戶信息:{}", userMessageJsonObject.toJSONString()); // { // "openid":" OPENID", // "nickname": NICKNAME, // "sex":"1", // "province":"PROVINCE" // "city":"CITY", // "country":"COUNTRY", // "headimgurl": "http://wx.qlogo.cn/mmopen/g3MoCfHe/46", // "privilege":[ // "PRIVILEGE1" // "PRIVILEGE2" // ], // "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" // }if (userMessageJsonObject != null) {try {//用戶昵稱nickName = userMessageJsonObject.getString("nickname");//用戶性別sex = userMessageJsonObject.getString("sex");sex = (sex.equals("1")) ? "男" : "女";//用戶唯一標識openid = userMessageJsonObject.getString("openid");logger.info("用戶昵稱:{}", nickName);logger.info("用戶性別:{}", sex);logger.info("OpenId:{}", openid);} catch (JSONException e) {logger.error("獲取用戶信息失敗");}}} catch (JSONException e) {logger.error("獲取Web Access Token失敗");}}}return "登錄成功";} }服務器日志:
: 收到微信重定向跳轉. : 用戶同意授權,獲取code:021qx2lsdf1FuDi90DX2l90qx2le , state:STAT : getCodeUrl:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx222e333a20897ea3&redirect_uri=http://www.xxx.com/url&response_type=code&scope=snsapi_userinfo&state=STAT#wechat_redirect : get Access Token URL:https://api.weixin.qq.com/sns/oauth2/access_token?appid= wx222e333a20897ea3&secret=c9d547819089dd0059bf4b234234209e1&code=021qx2l90VHASD23SADDi90DX2l90qx2le&grant_type=authorization_code https://api.weixin.qq.com/sns/oauth2/access_token?appid= wx222e333a20897ea3&secret=c9d5478190ASDFAQWEb39691409e1&code=021qx2l90VHWPt1FuDi9WEQQWE0qx2le&grant_type=authorization_code : 請求到的Access Token:{"access_token":"64CDRyZVwASDADSADSF2WCtel0VSUzrD4fswL2cqy0yNcNXAc1NXBi-KgGD6RLARf3SSnzZyXl-dAe2-xIfRnCY3m23uRWLxj-uGWkxZI","refresh_token":"iaTZN1ASDFASDFApCAINItDYMYDKwjwZo9XwYfNyIUZadAasXyJCHsvAUc1A8KakXPiASDFSADFmebcAuqP6Zn4G5N7Vjls0Nssd2R_XqE","openid":"ojUgjt6tkI08QASDFASZLKgsVR24","scope":"snsapi_userinfo","expires_in":7200} : 獲取access_token成功! : WebAccessToken:64CDRyZVwASDFASDFACtel0VSUzrD4fswL2cqy0yNcNXAc1NXBi-KgGD6RLARf3SSnzZyXl-dAe2-xIfRnCY3m23uRWLxj-uGWkxZI , openId:ojUgjt6tkI08QzSfqgzZLKgsVR24 : 獲取用戶信息的URL:https://api.weixin.qq.com/sns/userinfo?access_token=64CDRyZVwc7fwASDFASDFASDFASDFASDFASDcqy0yNcNXAc1NXBi-KgGD6RLARf3SSnzZyXl-dAe2-xIfRnCY3m23uRWLxj-uGWkxZI&openid=ojUgjt6tASDFASDFASDFSADFzZLKgsVR24&lang=zh_CN https://api.weixin.qq.com/sns/userinfo?access_token=64CDRyZVwc7fwyLclOASDFASDFASDFSADFcqy0yNcNXAc1NXBi-KgGD6RLARf3SSnzZyXl-dAe2-xIfRnCY3m23uRWLxj-uGWkxZI&openid=ojUgjt6tkI08QzSfqgzZLKgsVR24&lang=zh_CN : 用戶信息:{"country":"中國","province":"廣東","city":"深圳","openid":"ojUgjt6ASDFASDFASDgzZLKgsVR24","sex":1,"nickname":"xiao","headimgurl":"http://wx.qlogo.cn/mmopen/llaPdPm9YKCcASDFASDFASDFWt5vVYbWWIwnhW2BJOJV8QEsem9OhP3gCLJWYUrGOPK232JEMof3THVVlH/0","language":"zh_CN","privilege":[]} : 用戶昵稱:xiao : 用戶性別:男 : OpenId:ojUgjt6tkI08QzSfASDFgasdagsVR24刷新access_token(如果需要)
由于access_token擁有較短的有效期,當access_token超時后,可以使用refresh_token進行刷新,refresh_token擁有較長的有效期(7天、30天、60天、90天),當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"}總結
以上是生活随笔為你收集整理的Spring Boot 微信-网页授权获取用户信息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云数据库PostgreSQL新人怎样上手
- 下一篇: 定时任务监控服务Healthchecks