第一種是基於微信公衆號進行登陸,第二種是基於微信開放平臺進行登陸。html
緣由是微信登陸不一樣於QQ登陸和微博登陸,微信登陸沒有提供輸入帳密碼登陸功能。微信只提供了掃碼登陸功能,若是是PC端進行登陸的話能夠用手機進行掃碼,可是若是是手機端打開二維碼是不能進行掃碼的,即使是長按二維碼識別功能,可是很是不友好。java
第一種是沒有本身的帳號體系,直接拉取微信用戶信息來進行網站登陸。web
第二種是有本身的帳號體系,受權成功後須要綁定本身的帳號。spring
兩種實現方式均可以,只是在向session中存用戶信息的時候是存用戶獲取的微信信息仍是根據獲取的微信信息(能夠根據openID和nickname進行對應查詢用戶)轉換爲本身系統內對應的帳戶信息。apache
若是用戶在微信客戶端中訪問第三方網頁,公衆號能夠經過微信網頁受權機制,來獲取用戶基本信息,進而實現業務邏輯。json
總的來講,分爲四部:api
一、引導用戶進入受權頁面贊成受權,獲取code數組
二、經過code換取網頁受權access_token(與基礎支持中的access_token不一樣)瀏覽器
三、若是須要,開發者能夠刷新網頁受權access_token,避免過時安全
四、經過網頁受權access_token和openid獲取用戶基本信息(支持UnionID機制)
利用受權的微信公衆號(若是沒有能夠用開發者工具的微信公衆號測試帳號)。
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)手機端微信內打開以下:(手機自帶的瀏覽器打開效果同上面)
到主頁:
點擊微信受權登陸:
微信公衆平臺主要爲公衆號服務,主要用於微信公衆號二次開發;微信開放平臺支持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、4六、6四、9六、132數值可選,0表明640*640正方形頭像),用戶沒有頭像時該項爲空 |
privilege | 用戶特權信息,json數組,如微信沃卡用戶爲(chinaunicom) |
unionid | 用戶統一標識。針對一個微信開放平臺賬號下的應用,同一用戶的unionid是惟一的。 |
建議:
開發者最好保存用戶unionID信息,以便之後在不一樣應用中進行用戶信息互通。
unionID是用戶統一標識。統一微信開放平臺下面統一用戶的unionID惟一,並且公衆號若是綁定微信開放平臺以後,公衆號接口獲取的信息也會加上unionID。
調用頻率限制
接口名 | 頻率限制 |
---|---|
經過code換取access_token | 1萬/分鐘 |
刷新access_token | 5萬/分鐘 |
獲取用戶基本信息 | 5萬/分鐘 |