轉載:微信開放平臺開發第三方受權登錄(二):PC網頁端

微信開放平臺開發第三方受權登錄(二):PC網頁端

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: http://www.javashuo.com/article/p-hlrkqhfr-hv.html

微信開放平臺開發系列文章:

微信開放平臺開發第三方受權登錄(一):開發前期準備html

微信開放平臺開發第三方受權登錄(二):PC網頁端java

微信開放平臺開發第三方受權登錄(三):Android客戶端web

微信開放平臺開發第三方受權登錄(四):微信公衆號redis

微信開放平臺開發第三方受權登錄(五):微信小程序spring

 

目錄數據庫

1、需求apache

2、開發流程json

1.網站應用:(微信客戶端掃碼受權登錄)小程序

3、開發使用的技術及工具微信小程序

4、具體實現步驟

一、網站應用

1)請求獲取Code

2)用戶贊成受權與否

3)獲取access_token

4)經過access_token調用接口獲取用戶我的信息(UnionID機制)

5)刷新access_token

5、測試結果

一、網站應用

6、應用關鍵參數位置


微信開放平臺第三方受權登錄開發文檔(PC網頁端)

  當微信開放平臺開發第三方受權登錄(一):開發前期準備完成後,已經獲取到應用的AppID和AppSecret、且已經成功申請到微信登錄功能。能夠進行第三方登錄受權開發。

網站應用微信登陸是基於OAuth2.0協議標準構建的微信OAuth2.0受權登陸系統。

1、需求

根據需求,須要擁有第三方微信登陸功能,並獲取到用戶信息。

2、開發流程

1.網站應用:(微信客戶端掃碼受權登錄)

1)第三方發起微信受權登陸請求,微信用戶容許受權第三方應用後,微信會拉起應用或重定向到第三方網站,而且帶上受權臨時票據code參數;

2)經過code參數加上AppID和AppSecret等,經過API換取access_token;

3)經過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操做。

網站應用第三方受權登錄獲取用戶信息

3、開發使用的技術及工具

一、使用IDEA2017.2進行開發

二、使用SpringBoot進行快速開發

三、使用redis進行緩存。

四、使用fastJson對json數據進行處理

五、使用Maven對項目進行管理

4、具體實現步驟

一、網站應用

建立工程

打開IDEA,新建一個工程,選擇Spring Initializr,Next。而後填寫工程基本信息

選擇SpringBoot的版本已經須要添加的依賴,也能夠直接跳過,手動添加依賴。因爲是web工程,須要添加web相關依賴。模板引擎採用springboot推薦的thymeleaf。最後點擊確認,進入工程。

 

添加相關依賴

  1.    <dependency>
  2.       <groupId>org.apache.commons</groupId>
  3.       <artifactId>commons-lang3</artifactId>
  4.       <version>3.5</version>
  5.    </dependency>
  6.    <dependency>
  7.       <groupId>com.alibaba</groupId>
  8.       <artifactId>fastjson</artifactId>
  9.       <version>1.2.4</version>
  10.    </dependency>
  11.    <!-- 添加httpclient支持 -->
  12.    <dependency>
  13.       <groupId>org.apache.httpcomponents</groupId>
  14.       <artifactId>httpclient</artifactId>
  15.       <version>4.5.2</version>
  16.    </dependency>
  17.    <dependency>
  18.       <groupId>redis.clients</groupId>
  19.       <artifactId>jedis</artifactId>
  20.       <version>2.8.1</version>
  21.       <type>jar</type>
  22.    </dependency>

添加配置文件

SpringBoot默認會將resources下的application名字開頭的properties做爲配置文件。因此只須要添加application.properties就能夠了

因爲是使用thymeleaf做爲模板引擎。能夠添加相應的配置:

  1. #thymelea模板配置
  2. spring.thymeleaf.prefix=classpath:/templates/
  3. spring.thymeleaf.suffix=.html
  4. spring.thymeleaf.mode=HTML5
  5. spring.thymeleaf.encoding=UTF -8
  6. spring.thymeleaf.content-type= text/html
  7. spring.thymeleaf.cache= false
  8. spring.resources.chain.strategy.content.enabled= true
  9. spring.resources.chain.strategy.content.paths=/**

爲了讓系統更具備通用性,分別建立application-dev.properties、application-prod.properties對不一樣的環境進行配置。

在application.properties中,使用spring.profiles.active進行配置環境的選擇。

如:spring.profiles.active = prod

 

如:application-prod.properties

  1. ## 微信開放平臺
  2. # APPID
  3. wechat.open.appid =
  4. # APPSECRET
  5. wechat.open.appsecret =
  6. # 回調地址
  7. wechat.open.redirect_uri =

新建javaBean:WeChatUserInfo.java

  1. @Getter @Setter @ToString
  2. public class WeChatUserInfo {
  3.     String openid;
  4.     String nickname;
  5.     Integer sex;
  6.     String province;
  7.     String city;
  8.     String country;
  9.     String headimgurl;
  10.     String privilege;
  11.     String unionid;
  12.  
  13. }

新建WeChatOpenLoginController.java實現微信開放平臺第三方登陸的主要邏輯。

根據文檔進行編寫代碼。

 

1)請求獲取Code

前提:應用已經獲取相應的網頁受權做用域(scope=snsapi_login)

開發:第三方網站引導用戶打開連接

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

參數說明:

參數

必須

說明

appid

應用惟一標識

redirect_uri

請使用urlEncode對連接進行處理

response_type

填code

scope

應用受權做用域,擁有多個做用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login便可

state

用於保持請求和回調的狀態,受權請求後原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求僞造攻擊),建議第三方帶上該參數,可設置爲簡單的隨機數加session進行校驗

 

注意:若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,如redirect_uri的域名與審覈時填寫的受權域名不一致或scope不爲snsapi_login。


  

  1.   @RequestMapping("/login")
  2.     public String openWeChatLogin(HttpServletRequest httpServletRequest) {
  3.         // 防止csrf攻擊(跨站請求僞造攻擊)
  4.         String state = UUID.randomUUID().toString().replaceAll( "-", "");
  5.         // 採用redis等進行緩存state 使用sessionId爲key 30分鐘後過時,可配置
  6.         RedisPoolUtil.setEx( "wechat-open-state-" + httpServletRequest.getSession().getId(), state, Integer.parseInt(env.getProperty("wechat.open.exTime", "1800")));
  7.         String url = "https://open.weixin.qq.com/connect/qrconnect?" +
  8.                 "appid=" +
  9.                 env.getProperty( "wechat.open.pc.appid").trim() +
  10.                 "&redirect_uri=" +
  11.                 env.getProperty( "application.url") +
  12.                 env.getProperty( "wechat.open.pc.redirect_uri").trim() +
  13.                  "&response_type=code" +
  14.                 "&scope=snsapi_login" +
  15.                 "&state=" +
  16.                 state +     // 由後臺自動生成
  17.                  "#wechat_redirect";
  18.         return "redirect:" + url;
  19.     }

2)用戶贊成受權與否

用戶容許受權後,將會重定向到redirect_uri的網址上,而且帶上code和state參數

redirect_uri?code=CODE&state=STATE

若用戶禁止受權,則不會重定向到咱們提供的回調地址中

 

成功受權後,將得到Code,經過Code能夠獲取access_token

 

3)獲取access_token

經過上述方法獲取的code獲取access_token.

Http Get請求

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

 

請求後,

返回成功的json串爲(樣例):

{
"access_token":"ACCESS_TOKEN",        // 接口調用憑證
"expires_in":7200,                      // access_token接口調用憑證超時時間,單位(秒)
"refresh_token":"REFRESH_TOKEN",       //用戶刷新access_token
"openid":"OPENID",                                  //受權用戶惟一標識
"scope":"SCOPE",                                     //用戶受權的做用域,使用逗號(,)分隔
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"  //當且僅當該網站應用已得到該用戶的userinfo受權時,纔會出現該字段
}

失敗返回的樣例:

{"errcode":40029,"errmsg":"invalid code"}

失敗可能緣由:  暫時不明

  1.     @RequestMapping( "/callback/pc")
  2.     public String openWeChatCallback(HttpServletRequest httpServletRequest, Model model) {
  3.         String code = httpServletRequest.getParameter("code");
  4.         String state = httpServletRequest.getParameter("state");
  5.         String url = null;
  6.         // 判斷state是否合法
  7.         String stateStr = RedisPoolUtil.get("wechat-open-state-" + httpServletRequest.getSession().getId());
  8.         if (StringUtils.isEmpty(code) || StringUtils.isEmpty(stateStr) || !state.equals(stateStr)) {
  9.             throw new WechatParamException("非法參數,請從新登錄", "/");
  10.         }
  11.         url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
  12.                 "appid=" +
  13.                 env.getProperty( "wechat.open.pc.appid").trim() +
  14.                 "&secret=" +
  15.                 env.getProperty( "wechat.open.pc.appsecret").trim() +
  16.                 "&code=" +
  17.                 code +
  18.                 "&grant_type=authorization_code";
  19.         JSONObject wechatAccessToken = HttpClientUtils.httpGet(url);
  20.         if (wechatAccessToken.get("errcode") != null) {
  21.             throw new WechatParamException("獲取accessToken失敗", "/wechat/open/login");
  22.         }
  23.         String accessToken = (String) wechatAccessToken.get("access_token");
  24.         String openid = (String) wechatAccessToken.get("openid");
  25.         String unionid = (String) wechatAccessToken.get("unionid");
  26.         if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openid) || StringUtils.isEmpty(unionid)) {
  27.             throw new WechatParamException("獲取accessToken失敗", "/wechat/open/login");
  28.         }
  29.         // TODO:根據Openid或Unionid對數據庫進行查詢,若是查詢到對應的用戶數據,則不須要再向微信服務器發送請求去返回數據。
  30.         // TODO: 建議使用Unionid做爲查詢條件。
  31.         WeChatUserInfo weChatUserInfo = null;
  32.         wechatAccessToken = null;  // FIXME: 這裏應該是從數據庫中查詢獲取用戶信息邏輯。
  33.         if (wechatAccessToken == null) {
  34.             // 新用戶
  35.             weChatUserInfo = getUserInfoByAccessToken(accessToken);
  36.             // 數據庫插入的操做
  37.         }
  38.         if (weChatUserInfo != null) {
  39.             model.addAttribute(weChatUserInfo);
  40.             return "wechatUser";
  41.         }
  42.         throw new WechatParamException("獲取用戶信息失敗", "/wechat/open/login");
  43.     }

4)經過access_token調用接口獲取用戶我的信息(UnionID機制)

前提:

1. access_token有效且未超時;

2. 微信用戶已受權給第三方應用賬號相應接口做用域(scope)。

Http Get請求:

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

參數

是否必須

說明

access_token

調用憑證

openid

普通用戶的標識,對當前開發者賬號惟一

lang

國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語,默認爲zh-CN

 

返回成功的json結果(樣例):

{
"openid":"OPENID",        //普通用戶的標識,對當前開發者賬號惟一
"nickname":"NICKNAME",   //普通用戶暱稱
"sex":1,                                //普通用戶性別,1爲男性,2爲女性
"province":"PROVINCE",      //普通用戶我的資料填寫的省份
"city":"CITY",                        //普通用戶我的資料填寫的城市
"country":"COUNTRY",         //國家,如中國爲CN
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",       //用戶頭像,最後一個數值表明正方形頭像大小(有0、4六、6四、9六、132數值可選,0表明640*640正方形頭像),用戶沒有頭像時該項爲空
"privilege":[   //用戶特權信息,json數組,如微信沃卡用戶爲(chinaunicom)
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"   //用戶統一標識。針對一個微信開放平臺賬號下的應用,同一用戶的unionid是惟一的
}

 

失敗JSON樣例:

{"errcode":40003,"errmsg":"invalid openid"}

 

注意:在用戶修改微信頭像後,舊的微信頭像URL將會失效,所以開發者應該本身在獲取用戶信息後,將頭像圖片保存下來,避免微信頭像URL失效後的異常狀況

最好保存用戶unionID信息,以便之後在不一樣應用中進行用戶信息互通。

  1. private WeChatUserInfo getUserInfoByAccessToken( String accessToken) {
  2.         if (StringUtils.isEmpty(accessToken)) {
  3.             return null;  //"accessToken爲空";
  4.         }
  5.         String get_userInfo_url = null;
  6.         get_userInfo_url = "https://api.weixin.qq.com/sns/userinfo?" +
  7.                 "access_token=" +
  8.                 accessToken +
  9.                 "&openid=" +
  10.                 env.getProperty( "wechat.open.pc.appid").trim();
  11.         String userInfo_result = HttpClientUtils.httpGet(get_userInfo_url, "utf-8");
  12.         if (!userInfo_result.equals("errcode")) {
  13.             WeChatUserInfo weChatUserInfo = JSON.parseObject(userInfo_result, new TypeReference<WeChatUserInfo>() {
  14.             });
  15.             // TODO: 須要把頭像信息下載到文件服務器,而後替換掉頭像URL。微信的或許不可靠,假設微信用戶更換了頭像,舊頭像URL是否會保存?而這個URL信息卻存放在咱們的數據庫中,不可靠
  16.             return weChatUserInfo;
  17.         }
  18.         return null;  //"獲取用戶信息失敗"
  19.     }

5)刷新access_token

因爲access_token有效期(目前爲2個小時)較短,當access_token超時後,可使用refresh_token進行刷新,access_token刷新結果有兩種:

1. 若access_token已超時,那麼進行refresh_token會獲取一個新的access_token,新的超時時間;
2. 若access_token未超時,那麼進行refresh_token不會改變access_token,但超時時間會刷新,至關於續期access_token。

refresh_token擁有較長的有效期(30天),當refresh_token失效的後,須要用戶從新受權。

 

請求方法:

獲取第一步的code後,請求如下連接進行refresh_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參數

 

成功返回的結果:

{
"access_token":"ACCESS_TOKEN",    //接口調用憑證
"expires_in":7200,                             // access_token接口調用憑證超時時間,單位(秒)
"refresh_token":"REFRESH_TOKEN",   //用戶刷新access_token
"openid":"OPENID",                          //受權用戶惟一標識
"scope":"SCOPE"                              //用戶受權的做用域,使用逗號(,)分隔
}

失敗樣例:

{"errcode":40030,"errmsg":"invalid refresh_token"}

 

注意:

一、Appsecret 是應用接口使用密鑰,泄漏後將可能致使應用數據泄漏、應用的用戶數據泄漏等高風險後果;存儲在客戶端,極有可能被惡意竊取(如反編譯獲取Appsecret);
二、access_token 爲用戶受權第三方應用發起接口調用的憑證(至關於用戶登陸態),存儲在客戶端,可能出現惡意獲取access_token 後致使的用戶數據泄漏、用戶微信相關接口功能被惡意發起等行爲;
三、refresh_token 爲用戶受權第三方應用的長效憑證,僅用於刷新access_token,但泄漏後至關於access_token 泄漏,風險同上。

建議將secret、用戶數據(如access_token)放在App雲端服務器,由雲端中轉接口調用請求。

 

5、測試結果

一、網站應用

首先開啓redis。而後運行代碼。因爲SpringBoot會使用內置的Tomcat容器進行管理,直接運行就能夠了,而後點擊微信登陸。彈出掃碼登陸窗口,手機掃碼贊成登陸後就能夠獲取到用戶信息了.

 

6、應用關鍵參數位置

APPID和APPSecret以及回調地址位置,注:須要修改受權回調域,即回調地址

 

 

微信開放平臺開發第三方受權登錄(一):開發前期準備
[Wēixìn kāifàng píngtái kāifā dì sānfāng shòuquán dēnglù (yī): Kāifā qiánqí zhǔnbèi]
WeChat open platform for third-party developers authorized landing (a): the development preparatory
相關文章
相關標籤/搜索