1. 微信登錄的兩種實現方式
第一種是基於微信公眾號進行登錄,第二種是基於微信開放平台進行登錄。
原因是微信登錄不同於QQ登錄和微博登錄,微信登錄沒有提供輸入賬密碼登錄功能。微信只提供了掃碼登錄功能,如果是PC端進行登錄的話可以用手機進行掃碼,但是如果是手機端打開二維碼是不能進行掃碼的,即便是長按二維碼識別功能,但是非常不友好。
2.微信登錄的實現方式也有兩種
第一種是沒有自己的賬號體系,直接拉取微信用戶信息來進行網站登錄。
第二種是有自己的賬號體系,授權成功后需要綁定自己的賬號。
兩種實現方式都可以,只是在向session中存用戶信息的時候是存用戶獲取的微信信息還是根據獲取的微信信息(可以根據openID和nickname進行對應查詢用戶)轉換為自己系統內對應的賬戶信息。
3.基於微信公眾號進行授權登錄
1.簡介
如果用戶在微信客戶端中訪問第三方網頁,公眾號可以通過微信網頁授權機制,來獲取用戶基本信息,進而實現業務邏輯。
總的來說,分為四部:
1、引導用戶進入授權頁面同意授權,獲取code
2、通過code換取網頁授權access_token(與基礎支持中的access_token不同)
3、如果需要,開發者可以刷新網頁授權access_token,避免過期
4、通過網頁授權access_token和openid獲取用戶基本信息(支持UnionID機制)
2.進行授權
利用授權的微信公眾號(如果沒有可以用開發者工具的微信公眾號測試賬號)。
1.到接口設置修改域名
2. 邏輯分析(刷新access_token暫時不考慮)
第一步:用戶同意授權,獲取code
接口地址如下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
尤其注意:由於授權操作安全等級較高,所以在發起授權請求時,微信會對授權鏈接做正則強匹配校驗,如果鏈接的參數順序不對,授權頁面將無法正常訪問
參數說明如下:
下圖為scope等於snsapi_userinfo時的授權頁面:
如果用戶同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。
code說明 : code作為換取access_token的票據,每次用戶授權帶上的code將不一樣,code只能使用一次,5分鍾未被使用自動過期。
第二步:通過code換取網頁授權access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
請注意,這里通過code換取的是一個特殊的網頁授權access_token,與基礎支持(素材管理等操作)中的access_token(該access_token用於調用其他接口)不同。
第三步:拉取用戶信息(需scope為 snsapi_userinfo)
如果網頁授權作用域為snsapi_userinfo,則此時開發者可以通過access_token和openid拉取用戶信息了。
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 英語 |
3.代碼實現
WeixinAuthController代碼
package cn.qlq.controller.weixin; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSONObject; import cn.qlq.utils.HttpUtils; import cn.qlq.utils.weixin.WeixinConstants; @Controller @RequestMapping("weixin/auth") public class WeixinAuthController { /** * 首頁,跳轉到index.html,index.html有一個連接會訪問下面的login方法 * * @return */ @RequestMapping("/index") public String index() { return "weixinauth/index"; } /** * (一)微信授權:重定向到授權頁面 * * @return * @throws UnsupportedEncodingException */ @RequestMapping("/login") public String authorize() throws UnsupportedEncodingException { // 回調地址必須在公網可以訪問 String recirectUrl = URLEncoder.encode("http://6965ee39.ngrok.io/weixin/auth/calback.html", "UTF-8"); // 授權地址 String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"; url = url.replace("APPID", WeixinConstants.APPID).replace("REDIRECT_URI", recirectUrl); // 參數替換之后重定向到授權地址 return "redirect:" + url; } /** * (二)用戶同意授權; (三)微信會自動重定向到配置的URL並由SpringMVC分配到該方法並攜帶參數code和state用於換取access_token和openid; * (四) 用access_token和openid獲取用戶信息(五)如果有必要可以進行登錄,兩種:第一種是直接拿微信號登錄;第二種是根據openid和nickname獲取賬號進行登錄 * * @param code * @param state * @return * @throws UnsupportedEncodingException */ @RequestMapping("/calback") @ResponseBody public String calback(String code, String state) throws UnsupportedEncodingException { // 獲取access_token和openid String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; url = url.replace("APPID", WeixinConstants.APPID).replace("SECRET", WeixinConstants.APP_SECRET).replace("CODE", code); String doGet = HttpUtils.doGet(url, null); if (StringUtils.isNotBlank(doGet)) { JSONObject parseObject = JSONObject.parseObject(doGet); System.out.println(parseObject); // 獲取兩個參數之后獲取用戶信息 String accessToken = parseObject.getString("access_token"); String openid = parseObject.getString("openid"); String getUserInfoURL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN"; getUserInfoURL = getUserInfoURL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openid); String doGet2 = HttpUtils.doGet(getUserInfoURL, null); // 可以用獲取到的用戶信息進行兩種方式的登錄 System.out.println(doGet2); return doGet2; } return ""; } }
index.html:
<!doctype html> <html> <head> <meta http-equiv="Content-Type" contexnt="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> </head> <body style="font-size: 40px; text-align: center;"> <a href="/weixin/auth/login.html">微信授權登錄</a> </body> </html>
解釋:<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 是讓頁面自適應手機寬度。
測試:
(1)從PC端訪問頁面如下:
到主頁
點擊微信授權登錄:
(2)手機端微信內打開如下:(手機自帶的瀏覽器打開效果同上面)
到主頁:
點擊微信授權登錄:
4. 基於微信開放平台進行登錄
微信公眾平台主要為公眾號服務,主要用於微信公眾號二次開發;微信開放平台支持web應用、移動應該、公眾號整合等。
到微信開放平台注冊賬號之后並認證之后創建應用(目的是為了獲取獲取AppID和APPSecret),個人無法注冊測試賬號,所以無法測試,這里只是記錄接口文檔,由於步驟與上面大體一致,有需要的時候改一下就好。
接下來用APPID和APPSecret獲取用戶信息的步驟基本上與上面公眾號一樣。
微信開放平台網站:https://open.weixin.qq.com/
步驟也是如下:
第一步:請求 CODE
第三方使用網站應用授權登錄前請注意已獲取相應網頁授權作用域(scope=snsapi_login),則可以通過在PC端打開以下鏈接:
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
若提示“該鏈接無法訪問”,請檢查參數是否填寫錯誤,如redirect_uri的域名與審核時填寫的授權域名不一致或scope不為snsapi_login。
參數說明:
參數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 應用唯一標識 |
redirect_uri | 是 | 請使用urlEncode對鏈接進行處理 |
response_type | 是 | 填code |
scope | 是 | 應用授權作用域,擁有多個作用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即 |
state | 否 | 用於保持請求和回調的狀態,授權請求后原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該參數,可設置為簡單的隨機數加session進行校驗 |
用戶允許授權后,將會重定向到redirect_uri的網址上,並且帶上code和state參數(同上面公眾號一樣)
redirect_uri?code=CODE&state=STATE
若用戶禁止授權,則重定向后不會帶上code參數,僅會帶上state參數
redirect_uri?state=STATE
第二步:通過 code 獲取 access_token
接口地址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
參數說明:
參數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 應用唯一標識,在微信開放平台提交應用審核通過后獲得 |
secret | 是 | 應用密鑰AppSecret,在微信開放平台提交應用審核通過后獲得 |
code | 是 | 填寫第一步獲取的code參數 |
grant_type | 是 | 填authorization_code |
正確的返回:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }
第三步:通過access_token調用接口(可以跳過,說明步驟)
獲取access_token后,進行接口調用,有以下前提:
1. access_token有效且未超時;
2. 微信用戶已授權給第三方應用帳號相應接口作用域(scope)。
對於接口作用域(scope),能調用的接口有以下:
授權作用域(scope) | 接口 | 接口說明 |
---|---|---|
snsapi_base | /sns/oauth2/access_token | 通過code換取access_token、refresh_token和已授權scope |
snsapi_base | /sns/oauth2/refresh_token | 刷新或續期access_token使用 |
snsapi_base | /sns/auth | 檢查access_token有效性 |
snsapi_userinfo | /sns/userinfo | 獲取用戶個人信息 |
第四步:獲取用戶個人信息(UnionID 機制)
此接口用於獲取用戶個人信息。開發者可通過 OpenID 來獲取用戶基本信息。特別需要注意的是,如果開發者擁有多個移動應用、網站應用和公眾帳號,可通過獲取用戶基本信息中的 unionid 來區分用戶的唯一性,因為只要是同一個微信開放平台帳號下的移動應用、網站應用和公眾帳號,用戶的 unionid 是唯一的。換句話說,同一用戶,對同一個微信開放平台下的不同應用,unionid 是相同的。請注意,在用戶修改微信頭像后,舊的微信頭像 URL 將會失效,因此開發者應該自己在獲取用戶信息后,將頭像圖片保存下來,避免微信頭像 URL 失效后的異常情況。
接口地址:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
參數說明:
參數 | 是否必須 | 說明 |
---|---|---|
access_token | 是 | 調用憑證 |
openid | 是 | 普通用戶的標識,對當前開發者帳號唯一 |
lang | 否 | 國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語,默認為zh-CN |
正確的返回:
{ "openid":"OPENID", "nickname":"NICKNAME", "sex":1, "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" }
參數解釋:
參數 | 說明 |
---|---|
openid | 普通用戶的標識,對當前開發者帳號唯一 |
nickname | 普通用戶昵稱 |
sex | 普通用戶性別,1為男性,2為女性 |
province | 普通用戶個人資料填寫的省份 |
city | 普通用戶個人資料填寫的城市 |
country | 國家,如中國為CN |
headimgurl | 用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空 |
privilege | 用戶特權信息,json數組,如微信沃卡用戶為(chinaunicom) |
unionid | 用戶統一標識。針對一個微信開放平台帳號下的應用,同一用戶的unionid是唯一的。 |
建議:
開發者最好保存用戶unionID信息,以便以后在不同應用中進行用戶信息互通。
unionID是用戶統一標識。統一微信開放平台下面統一用戶的unionID唯一,而且公眾號如果綁定微信開放平台之后,公眾號接口獲取的信息也會加上unionID。
調用頻率限制
接口名 | 頻率限制 |
---|---|
通過code換取access_token | 1萬/分鍾 |
刷新access_token | 5萬/分鍾 |
獲取用戶基本信息 | 5萬/分鍾 |