微信第三方登錄 -- (PC端+移動端)


微信第三方登錄 -- (PC端+移動端)

 

一、前言

一. 什么是第三方登錄

所謂的第三方登錄,是說基於用戶在第三方平台上已有的賬號和密碼來快速完成己方應用的登錄或者注冊的功能。而這里的第三方平台,一般是已經擁有大量用戶的平台,國外的比如Facebook,Twitter等,國內的比如微博、微信、QQ等。

二. 為什么要用第三方登錄

第三方登錄之所以會被較為廣泛地在產品設計上使用,是因為它有以下幾個優點:

(1)對普通用戶

相比於本地注冊,第三方登錄一般來說比較方便、快捷,能夠顯著降低用戶的注冊和登錄成本,方便用戶實現快捷登錄或注冊。不用費盡心思地應付本地注冊對賬戶名和密碼的各種限制,如果不考慮昵稱的重復性要求,幾乎可以直接一個賬號走遍天下,再也不用在大腦或者什么地方記住N多不同的網站或App的賬號和密碼,整個世界一下子清靜了。在第一次綁定成功之后,之后用戶便可以實現一鍵登錄,使得后續的登錄操作比起應用內的登錄來容易了很多。對於某些喜歡社交,並希望將更多自己的生活內容展示給朋友的人來說,第三方登錄可以實現把用戶在應用內的活動同步到第三方平台上,省去了用戶手動發布動態的麻煩。但對於某些比較注重個人隱私的用戶來說,則會有一些擔憂,所以說這個優點是有前提的。

(2)對應用

因為降低了用戶的注冊或登錄成本,從而減少由於本地注冊的繁瑣性而帶來的隱形用戶流失,最終提高注冊轉化率。對於某些應用來說,使用第三方登錄完全可以滿足自己的需要,因此不必要設計和開發一套自己的賬戶體系。通過授權,可以通過在第三方平台上分享用戶在應用內的活動在第三方平台上宣傳自己,從而增加產品知名度。通過授權,可以獲得該用戶在第三方平台上的好友或粉絲等社交信息,從而后續可以針對用戶的社交關系網進行有目的性的營銷宣傳,為產品的市場推廣提供另一種渠道。

(3)對第三方

增加用戶對平台的依賴,用戶越多使用本平台的第三方登錄,就代表着平台對該用戶的粘性越高。獲得更廣泛的影響力,只要用戶使用提供第三方登錄的應用,那么這個提供第三方登錄的品牌就會被用戶瀏覽,有利於對平台的拉新和促活。

三. 使用第三方登錄要注意的地方

任何事物都是有兩面性的,盡管第三方登錄具有以上所述的優點,但同時也存在着一定的問題需要注意,供大家參考:

(1)對用戶

一旦自己的第三方賬戶出現問題,比如被第三方平台封號,或者賬號被盜,則會發生相應的應用內數據丟失或者數據泄露。這個時候即使注冊一個新賬戶,之前在應用內所有的記錄也是無法恢復的。

(2)對應用

對於有自己本地注冊需求,並且提供第三方登錄的應用而言,需要考慮第三方賬號和本地賬號的對接問題,產品需要設計對接方案,研發也要正確實現這個對接方案,會帶來一定的額外工作量;此外,如果這個問題處理不好,很容易導致同一個用戶在應用上存在多個賬號的情況,為用戶在平台上的操作帶來了困擾。一旦第三方登錄出現問題,比如出現服務宕機,或者停止提供登錄服務,將會對應用的后續發展造成一定的風險。

四. 第三方登錄的實現方式

目前第三方登錄的實現方式一般來講有兩種:

純登錄登錄+賬號綁定

下面來看看這兩種實現方式的細節:

1. 純登錄方式

(1)實現策略

使用第三方賬號直接登錄,即可擁有完整的同本地注冊用戶相同的待遇。

(2)優勢

簡單、快捷,用戶第一次只需要登錄第三方平台並將登錄許可授權給應用即可,只要成功,后續就能像應用注冊用戶一樣使用應用內所有服務。

(3)劣勢

賬號體系在別人手里,一旦第三方登錄出現問題,會面臨用戶及用戶數據丟失的風險,給應用的可持續發展帶來一定的隱患,只是,考慮到目前提供第三方登錄的平台的實力,這種隱患的發生是一個小概率事件。

(4)適用場景

如果你所開發的應用定位與分享、評論、社交,並不涉及必須進行創建應用賬號的復雜功能,是比較輕量級的應用,那么你可以選擇放棄自主的應用賬號體系。比如今日頭條、一點資訊等資訊類應用,還有網易雲音樂等音樂類應用。

2. 登錄+綁定方式

 

使用第三方登錄后,要求綁定應用內賬戶(如果用戶有,則直接綁定,否則需要走應用內的賬號注冊流程)。

這種實現方式總體上來講,對應用和用戶都是有一定好處的。

對應用來講:

可以將用戶信息牢牢抓在自己手里,防止被第三方拒絕提供服務后丟失本應用積累的用戶;可以拿到更多用戶的聯系信息,比如郵箱、手機號碼等,可以為后續的持續營銷打下基礎;可以避免一個用戶多個賬號同時存在的情況發生。

對用戶來講:主要是可以防止第三方登錄關閉登錄服務之后,無法找到自己在應用內的信息的風險。

至於具體的綁定方式,有兩種常規的做法:立即綁定和延時綁定。接下來筆者將分別聊聊。

1)實現方式

使用第三方登錄后立即需要綁定應用內賬號。

2)優勢

使得應用內的賬號體系比較規整,避免同一個用戶產生不同的賬號,也進一步避免了同一個用戶不同賬號之間的數據合並工作。

3)劣勢

這種方式給用戶的體驗不太好,尤其是用戶沒有本地賬號的時候,真的很讓人討厭啊,不但么有減輕用戶的注冊成本,反而增加了,給用戶的感覺是還不如直接注冊,多此一舉。

4)適用場景

對於店大的應用,你完全可以這么干,比如京東、唯品會這種級別的,因為你對用戶的吸引力足夠,他為了獲得應用的服務,能夠忍受這樣的額外麻煩。

但對於剛起步的應用,拉新是比較重要的任務和業績指標,這么干則有一定的風險,因為這樣的用戶體驗是非常糟糕的,用戶很可能因為這個設計而罵娘,然后棄你而去。

(2)登錄+延時綁定賬號

1)實現策略

將第三方登錄和賬號綁定進行解耦,用戶在第三方登錄后會獲得部分本地注冊用戶的權限,但在一些關鍵點上卡住,引導用戶綁定一個本地賬號,這種做法在用戶的便捷性和應用的安全性上取得了一個最好的平衡。

2)優勢

降低注冊成本,迅速將第三方登錄帶來的流量留在應用內,提高應用的注冊轉化率;給用戶的體驗更貼近於用戶的期望(因為登錄之后再登錄用戶很難理解的),第三方登錄后可以使用應用了,哪怕是部分功能。

3)劣勢

會造成一個用戶在綁定應用內賬號之前會擁有多個的個人賬戶:一來給用戶的使用造成一定的困擾,二來會因為后續的賬號合並帶來一定的產品和研發工作量。

4)適用場景

比較適合於剛起步階段,同時僅僅第三方登錄滿足不了全部功能需要的應用,比如電商或者O2O類型的應用,因為這樣的應用一般會需要用戶的手機號,而這個信息第三方登錄是提供不了的。

結論

最后結論就是應用賬號登錄與第三方登錄均有利弊,無論何種選擇,力求尊重用戶,為用戶帶來方便這個大方向總是不錯的。至於具體選擇,則要結合自己產品的形態、定位、風格以及願景來進行選擇,不同場景使用不同的實現方式,具體問題具體分析,任何試圖用一個方子處理所有問題的企圖都是有風險的。

 

二、請求code (GET請求)

注:請求code僅限於PC端。移動端(APP)由於java無法控制用戶手機 拉起(用戶手機中)微信應用。所以移動端code由Android和iOS請求、做回調獲取code,然后作為參數傳給java后台!(僅個人理解,如有不對的地方。望指正、並忽略)

接口地址:https://open.weixin.qq.com/connect/qrconnect?appid=wx4530e35e8a9fc5cd&redirect_uri=http://www.mogujie.com/oauth/callback/weixin/mogujie?referer_key=5E6BA887B6F2988918AD730D730D8D69&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect

 

(點擊鏈接:可拉起蘑菇街網站'微信二維碼'登錄頁面)

 

一、接下來就借助這個鏈接中的幾個參數,做詳細解釋:

appid:是在微信開方平台申請的'應用唯一標識,在微信開放平台提交應用審核通過后獲得';

redirect_uri:是在微信開方平台申請時填寫'返回code的回調地址';

關於redirect_uri回調地址后面的referer_key參數說明:

這個參數可以在后台拼接code請求地址時:加上一個參數,對這個參數生成一個時間戳或uuid、隨機數(存入session)。然后拼接到redirect_uri回調地址的后面,這樣當你寫回調方法的時候可以獲取下你在請求code時生成的參數。然后(和session的參數)做下校驗用於保持請求和回調的狀態,防止跨站請求偽造攻擊。

**state參數和referer_key是一樣的作用**

response_type:是需要返回的類型,固定填code;

scope:為授權作用域,有兩種'snsapi_base'和'snsapi_userinfo'

關於網頁授權的兩種scope的區別說明
1、以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的用戶的openid的,並且是靜默授權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(往往是業務頁面)             - - 靜默授權
2、以snsapi_userinfo為scope發起的網頁授權,是用來獲取用戶的基本信息的。但這種授權需要用戶手動同意,並且由於用戶同意過,所以無須關注,就可在授權后獲取該用戶的基本信息。  - - 手動授權

state:生成一個時間戳或uuid、隨機數用於保持請求和回調的狀態,授權請求后原樣帶回給第三方(此參數也可以忽略不傳);

 

二、微信官方對這幾個參數的解釋:

參數 是否必須 說明
appid 應用唯一標識
redirect_uri 請使用urlEncode對鏈接進行處理
response_type 填code
scope 應用授權作用域,擁有多個作用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即
state 用於保持請求和回調的狀態,授權請求后原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該參數,可設置為簡單的隨機數加session進行校驗


三、請求code代碼

/**微信請求地址 */ //獲取code 接口地址 Get public final static String WEB_CODE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"; //微信回調地址(獲取code) public final static String REDIRECT_URI = "http://服務器域名:端口號(如為80,可忽略端口號)/*****/weixin/*****"; /** * 拼接獲取code的:接口地址 * @param state 狀態碼 * @return */ public static String getCodeURL(String state) { return WEB_CODE_URL.replace("APPID",APPID).replace("REDIRECT_URI",REDIRECT_URI).replace("SCOPE",SCOPE).replace("STATE",state); }

 

四、回調方法:

controller層:

@RestController @RequestMapping("/*****") public class WXController {         @Autowired         private WXService weXService; @RequestMapping(value = "/weixin/*****")         public JsonResult  WXLogin(HttpServletRequest request) {                 return weXService.WXLogin(request);         } }

service層:

public interface WXService {     JsonResult WXLogin(HttpServletRequest request); }

serviceImpl層:

@Service public class WXServiceImpl {     @Override     public JsonResult WXLogin(HttpServletRequest request) {         //創建一個統一返回對象         JsonResult jsonResult = new JsonResult();         /**          *微信請求回調格式:          *  允許授權:          *         redirect_uri?code=CODE&state=STATE          *  禁止授權:          *         redirect_uri?state=STATE          */         //獲取回調地址中的參數code         String code = request.getParameter("code");         //獲取回調地址中的參數state         String state = request.getParameter("state");         //從session中取出state狀態碼         Object sessionState = request.getSession().getAttribute("state");         //校驗回調中的state和session中的sessionState是否一致(防止:跨站請求偽造攻擊)         if (sessionState.toString().equals(state)) {             //校驗回調中的code,是否為空             if (ObjectUtil.isNotEmpty(code)) {                 //根據code向微信服務器發送請求,獲取返回參數                 AccessToken accessToken = WeChatUtils.getAccessToken(code);                 //判斷微信服務器返回的access_token是否為空                 if (ObjectUtil.isNotEmpty(accessToken.getAccess_token())) {                     //根據access_token和openid向微信服務器發送請求,獲取微信用戶信息                     WeChatUser weChatUserInfo = WeChatUtils.getWeChatUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());                     //根據返回的openid是否為空,判斷'微信用戶信息'是否成功獲取                     if (ObjectUtil.isNotEmpty(weChatUserInfo.getOpenid())) {                          /*                           * 在此處編寫具體業務的邏輯!!!                           *                           * 在此處編寫具體業務的邏輯!!!                           *                           * 在此處編寫具體業務的邏輯!!!                           */                               }                     } else {                         System.out.println("微信用戶信息獲取失敗:錯誤編碼 >> "+weChatUserInfo.getErrcode()+"。錯誤信息 >> "+weChatUserInfo.getErrmsg());                         jsonResult.setStatus(2);                         jsonResult.setData("微信用戶信息獲取失敗");                     }                 } else {                     System.out.println("微信授權異常:錯誤編碼 >> "+accessToken.getErrcode()+"。錯誤信息 >> "+accessToken.getErrmsg());                     jsonResult.setStatus(2);                     jsonResult.setMsg("微信授權異常");                 }             } else {                 jsonResult.setMsg("用戶未授權");                 jsonResult.setStatus(2);             }         } else {             jsonResult.setMsg("惡意請求");             jsonResult.setStatus(2);         }         return jsonResult;     } }

 

五、請求code完成,總結需要注意的點:

1.appid、redirect_uri、scope是必傳的,缺一不可!

 

***********************************************

***********************************************

***********************************************

 

2.在上面請求code中所用到的參數,appid、redirect_uri是需要在微信開放平台上申請的。(換言之,就是這兩個參數是要公司提供的

 

三、根據code,獲取access_token(GET請求)

接口地址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

一、接下來就借助這個鏈接中的幾個參數,做詳細解釋:

appid:同上;

secret:同上;

code:用戶授權后,微信服務器返回臨時憑證,用於換取access_token;(五分鍾有效期)

grant_type:在獲取access_token時,這是一個固定值的參數authorization_code;

 

二、微信官方對這幾個參數的解釋:

參數 是否必須 說明
appid 應用唯一標識,在微信開放平台提交應用審核通過后獲得
secret 應用密鑰AppSecret,在微信開放平台提交應用審核通過后獲得
code 填寫第一步獲取的code參數
grant_type 填authorization_code

 

三、請求access_token代碼

//獲取access_token 接口地址 Get public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; /** * 獲取授權登錄access_token * @param code 臨時授權憑證 * @return */ public static AccessToken getAccessToken(String code) { //拼接獲取access_token的請求地址 String accessTokenUrl = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("SECRET", APPSECRET).replace("CODE", code); //發送請求,獲取返回結果 JSONObject jsonObject = HttpsUtils.sendRequest(accessTokenUrl, "GET", null); //獲取返回的參數,並且封裝成AccessToken對象 AccessToken accessToken = new AccessToken(); if (jsonObject.getString("access_token") != null) { /** * 官方返回格式: * "access_token":"ACCESS_TOKEN", * "expires_in":7200, * "refresh_token":"REFRESH_TOKEN", * "openid":"OPENID", * "scope":"SCOPE", * "unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL" */ accessToken.setAccess_token(jsonObject.getString("access_token")); accessToken.setExpires_in(jsonObject.getString("expires_in")); accessToken.setRefresh_token(jsonObject.getString("refresh_token")); accessToken.setOpenid(jsonObject.getString("openid")); accessToken.setScope(jsonObject.getString("scope")); //UnionID機制 accessToken.setUnionid(jsonObject.getString("unionid")); } else { /** * 錯誤返回樣例: * "errcode":40029, * "errmsg":"invalid code" */ accessToken.setErrcode(jsonObject.getString("errcode")); accessToken.setErrmsg(jsonObject.getString("errmsg")); } return accessToken; }

 

四、根據access_token,獲取用戶信息(GET請求)

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

一、接下來就借助這個鏈接中的幾個參數,做詳細解釋:

access_token:根據臨時憑證code,獲取到的用戶有效憑證token,(有效期2小時);

openid:普通用戶的標識,對當前開發者帳號(也就是應用、網站)唯一。

二、微信官方對這幾個參數的解釋:

參數 是否必須 說明
access_token 調用憑證
openid 普通用戶的標識,對當前開發者帳號唯一

 

三、獲取用戶個人信息的代碼

//獲取userinfo 接口地址 Get public final static String WECHAT_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; /** * 獲取用戶信息 * @param accessToken * @param openid * @return */ public static WeChatUser getWeChatUserInfo(String accessToken,String openid) { //拼接獲取userinfo的請求地址 String userinfoUrl = WECHAT_USERINFO_URL.replace("ACCESS_TOKEN",accessToken).replace("OPENID",openid); //發送請求,獲取返回結果 JSONObject jsonObject = HttpsUtils.sendRequest(userinfoUrl, "GET", null); //獲取返回的參數,並且封裝成WeChatUser對象 WeChatUser weChatUser = new WeChatUser(); if (jsonObject.getString("openid") != null) { /** * 官方返回格式: * { * "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" * } */ weChatUser.setOpenid(jsonObject.getString("openid")); weChatUser.setNickname(jsonObject.getString("nickname")); weChatUser.setSex(jsonObject.getString("sex")); weChatUser.setProvince(jsonObject.getString("province")); weChatUser.setCity(jsonObject.getString("city")); weChatUser.setCountry(jsonObject.getString("country")); weChatUser.setHeadimgurl(jsonObject.getString("headimgurl")); weChatUser.setPrivilege(jsonObject.getString("privilege")); weChatUser.setUnionid(jsonObject.getString("unionid")); } else { /** * 錯誤返回樣例: * "errcode":40003, * "errmsg":"invalid openid" */ weChatUser.setErrcode(jsonObject.getString("errcode")); weChatUser.setErrmsg(jsonObject.getString("errmsg")); } return weChatUser; }

 

五、結尾

在本篇博客中所用的到所有工具類均在下面鏈接中可以找到,后續有時間會對代碼進行更新和加入其它的第三方登錄!

在下面鏈接中有在項目中的實際案例!可供參考...

項目源碼:https://gitee.com/qcxdld/open_logon


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM