時(shí)間:2022-08-10 15:30:01 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2022-08-10 15:30:01 來(lái)源:網(wǎng)站運(yùn)營(yíng)
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/Android.html
1、引導(dǎo)用戶進(jìn)入授權(quán)頁(yè)面同意授權(quán),獲取 code疑問(wèn) 1:scope 為 snsapi_base 和 scope 為 snsapi_userinfo 的區(qū)別?
2、通過(guò) code 換取網(wǎng)頁(yè)授權(quán) access_token(與基礎(chǔ)支持中的 access_token 不同)
3、如果需要,開(kāi)發(fā)者可以刷新網(wǎng)頁(yè)授權(quán) access_token,避免過(guò)期
4、通過(guò)網(wǎng)頁(yè)授權(quán) access_token 和 openid 獲取用戶基本信息(支持 UnionID 機(jī)制)
snsapi_base 是靜默授權(quán)并自動(dòng)跳轉(zhuǎn)到回調(diào)頁(yè)的,snsapi_userinfo 是需要用戶手動(dòng)同意。疑問(wèn) 2:網(wǎng)頁(yè)授權(quán) access_token 和普通 access_token 的區(qū)別?
普通 access_token 獲取用戶信息時(shí),如果用戶未關(guān)注,信息獲取就為空。而網(wǎng)頁(yè)授權(quán) access_token 的獲取,只要用戶許可,就可以獲得,不論用戶是否關(guān)注。疑問(wèn) 3:UnionID 和 openid 的區(qū)別?
unionid 對(duì)同一個(gè)微信開(kāi)放平臺(tái)下的不同應(yīng)用(移動(dòng)應(yīng)用、網(wǎng)站應(yīng)用和公眾帳號(hào))都是相同的。疑問(wèn) 4:關(guān)于UnionID機(jī)制
而 openid 對(duì)同一個(gè)微信開(kāi)放平臺(tái)下的不同應(yīng)用都是不相同的,如用戶授權(quán)應(yīng)用 A 和應(yīng)用 B,那么用戶的兩個(gè) openid 是不相同的,并且一個(gè)應(yīng)用對(duì)應(yīng)一個(gè) openid,如用戶在次授權(quán)給應(yīng)用 A,openid 不變。
即如果開(kāi)發(fā)者有多個(gè)公眾號(hào),或在公眾號(hào)、移動(dòng)應(yīng)用之間統(tǒng)一用戶帳號(hào)的需求,需要前往微信開(kāi)放平臺(tái)(http://open.weixin.qq.com)綁定公眾號(hào)后,才可利用UnionID機(jī)制來(lái)滿足上述需求。
解決:在公眾號(hào)設(shè)置-功能設(shè)置-網(wǎng)頁(yè)授權(quán),配置前端存放txt文件的路徑,如http://www.xxx.com/static,然后點(diǎn)擊提交,可以事先測(cè)一下能不能訪問(wèn)到txt的內(nèi)容。
解決:前往微信開(kāi)放平臺(tái),綁定該公眾號(hào),大功告成
# 微信相關(guān)配置wx: #商戶 ID MCH_ID: # 項(xiàng)目基礎(chǔ)域名 BASEURL: #微信登錄-用戶同意后回調(diào)域名(前端域名) URL: # 公眾號(hào)APP_ID H_APP_ID: # 公眾號(hào)秘鑰 H_APP_SECRET: # app的APP_ID A_APP_ID: # APP的 秘鑰 A_APP_SECRET: #微信登錄-微信授權(quán)基本地址 LOGIN_AUTH_BASE_URL: https://open.weixin.qq.com/connect/oauth2/authorize? #微信登錄-獲取ACCESS_TOKEN的URL LOGIN_ACCESS_TOKEN_URL: https://api.weixin.qq.com/sns/oauth2/access_token? #微信登錄-獲取登錄人信息的url LOGIN_USER_INFO_URL: https://api.weixin.qq.com/sns/userinfo? #微信登錄-用戶同意后回調(diào)地址(前端地址) LOGIN_RETURN_URL: ${wx.URL}/static/weixinShouQuan.html #微信登錄-應(yīng)用授權(quán)作用域,snsapi_base (不彈出授權(quán)頁(yè)面,直接跳轉(zhuǎn),只能獲取用戶openid), snsapi_userinfo #(彈出授權(quán)頁(yè)面,可通過(guò)openid拿到昵稱、性別、所在地。并且,即使在未關(guān)注的情況下,只要用戶授權(quán),也能獲取其信息 ) SCOPE: snsapi_userinfo
/** * 獲取yml參數(shù)實(shí)體 */@Component@Datapublic class YmlParament { /*微信相關(guān)字段*/ @Value("${wx.BASEURL}") private String baseurl; @Value("${wx.H_APP_ID}") private String h_app_id; @Value("${wx.A_APP_ID}") private String a_app_id; @Value("${wx.H_APP_SECRET}") private String h_app_secret; @Value("${wx.A_APP_SECRET}") private String a_app_secret; @Value("${wx.LOGIN_ACCESS_TOKEN_URL}") private String login_access_token_url; @Value("${wx.LOGIN_USER_INFO_URL}") private String login_user_info_url; @Value("${wx.LOGIN_AUTH_BASE_URL}") private String login_auth_base_url; @Value("${wx.LOGIN_RETURN_URL}") private String login_return_url; @Value("${wx.SCOPE}") private String scope;}
@ApiOperation("獲取授權(quán)url") @PostMapping("/getWeiXinLoginUrl") public R getWeiXinLoginUrl() throws Exception { String url = ymlParament.getLogin_auth_base_url() + "appid=" + ymlParament.getH_app_id()+ "&redirect_uri=" + ymlParament.getLogin_return_url()+ "&response_type=code"+ "&scope=snsapi_userinfo" + "&state=STATE#wechat_redirect"; //這里的R是自己自定義的 return R.ok().data("redirectUrl", url); }
-(void)sendAuthRequest{ //構(gòu)造SendAuthReq結(jié)構(gòu)體 SendAuthReq* req =[[[SendAuthReq alloc]init]autorelease]; req.scope = @"snsapi_userinfo"; req.state = @"123"; //第三方向微信終端發(fā)送一個(gè)SendAuthReq消息結(jié)構(gòu) [WXApi sendReq:req];}
Android 平臺(tái)應(yīng)用授權(quán)登錄接入代碼示例(請(qǐng)參考 Android 接入指南):{ // send oauth request Final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat_sdk_demo_test"; api.sendReq(req);}
/*H5和app都可以調(diào)用*/ @ApiOperation("獲取微信用戶信息") @PostMapping(value = "/getWxUserInFo") public R getWxUserInFo(@RequestBody String body) throws Exception { String state = JacksonUtil.parseString(body, "state"); String code = JacksonUtil.parseString(body, "code"); //標(biāo)志哪一個(gè)應(yīng)用,用來(lái)獲取對(duì)應(yīng)的appid和appsecret Integer openIdType = JacksonUtil.parseInteger(body, "openIdType"); //1、獲取code if(IsNull.isNull(code) || IsNull.isNull(state)) { return R.error("參數(shù)不能為空"); } //2、通過(guò)code獲取accesstoken,UserWxOpenidEums是用來(lái)記錄應(yīng)用的,如type1是xxAPP,type2是xx服務(wù)號(hào) JSONObject accessToken=WxUtils.getAccessTokenByCode(code, openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_id():ymlParament.getH_app_id(),openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_secret():ymlParament.getH_app_secret(),ymlParament.getLogin_access_token_url()); //3、獲取用戶信息 JSONObject userinfo=WxUtils.getUserinfo(openIdType==UserWxOpenidEums.TYPE_1.getKey()?ymlParament.getA_app_id():ymlParament.getH_app_id(),accessToken.getString("openid"), accessToken.getString("access_token"), ymlParament.getLogin_user_info_url()); if(!IsNull.isNull(userinfo.getString("errcode"))){ return R.error(userinfo.getString("errmsg")); } return R.ok().data("token", token).data("userinfo",userinfo);}
WxUtils/** * =============>>登錄<<============= * 第二步 * 通過(guò)code獲取access_token * 正確時(shí)返回的JSON數(shù)據(jù)包如下: * { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } */ public static JSONObject getAccessTokenByCode(String code,String appId,String appSecret,String login_access_token_url) throws Exception { Map<String, String> map = new HashMap<String, String>(); map.put("appid",appId); map.put("secret",appSecret); map.put("code",code); map.put("grant_type","authorization_code"); return (JSONObject)JSON.parse(HttpUtil.get(login_access_token_url, map)); } /** * =============>>登錄<<============= * 第三步:刷新access_token(如果需要) * 正確時(shí)返回的JSON數(shù)據(jù)包如下: * { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } */ public static JSONObject refreshAccessToken(String appid,String refresh_token) throws Exception { Map<String, String> map = new HashMap<>(); map.put("appid",appid); map.put("grant_type","refresh_token"); map.put("refresh_token",refresh_token); return (JSONObject)JSON.parse(HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/refresh_token?", map)); } /** * =============>>登錄<<============= * 第四部,獲取用戶信息 * 通過(guò)code獲取access_token * 正確時(shí)返回的JSON數(shù)據(jù)包如下: * { "openid":" OPENID", "nickname": NICKNAME, "sex":"1", "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46", "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ], "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" } * @throws Exception */ public static JSONObject getUserinfo(String appid,String openid,String accessToken,String login_user_info_url) throws Exception { //先判斷下accessToken是否有效 HashMap<String, String> param =new HashMap<String, String>(); param.put("access_token", accessToken); param.put("openid", openid); JSONObject check=(JSONObject)JSON.parse(HttpUtil.get("https://api.weixin.qq.com/sns/auth?access_token="+accessToken+"&openid="+openid, param)); //檢驗(yàn)授權(quán)憑證(access_token)是否有效,如果accessToken失效了,則刷新accessToken if(!check.getString("errcode").equals("0")) { accessToken=refreshAccessToken(appid, accessToken).getString("refresh_token"); } param =new HashMap<String, String>(); param.put("openid",openid); param.put("access_token",accessToken); param.put("lang","zh_CN"); return (JSONObject) JSON.parse(HttpUtil.get(login_user_info_url, param)); }
HttpUtilpublic static String get(String urlStr, Map<String, String> parameters) throws IOException { URL url = new URL(urlStr); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); // 設(shè)置該連接是可以輸出的 httpURLConnection.setRequestMethod("GET"); // 設(shè)置請(qǐng)求方式 httpURLConnection.setRequestProperty("charset", "utf-8"); PrintWriter pw = new PrintWriter(new BufferedOutputStream(httpURLConnection.getOutputStream())); StringBuffer parameter = new StringBuffer(); parameter.append("1=1"); for (Entry<String, String> entry : parameters.entrySet()) { parameter.append("&" + entry.getKey() + "=" + entry.getValue()); } pw.write(parameter.toString());// 向連接中寫數(shù)據(jù)(相當(dāng)于發(fā)送數(shù)據(jù)給服務(wù)器) pw.flush(); pw.close(); BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "utf-8")); String line = null; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { // 讀取數(shù)據(jù) sb.append(line + "/n"); } br.close(); return sb.toString(); }
JacksonUtilpublic class JacksonUtil { public static String parseString(String body, String field) { ObjectMapper mapper = new ObjectMapper(); JsonNode node; try { node = mapper.readTree(body); JsonNode leaf = node.get(field); if (leaf != null) { return leaf.asText(); } } catch (IOException e) { e.printStackTrace(); } return null; } public static Integer parseInteger(String body, String field) { ObjectMapper mapper = new ObjectMapper(); JsonNode node; try { node = mapper.readTree(body); JsonNode leaf = node.get(field); if (leaf != null) { return leaf.asInt(); } } catch (IOException e) { e.printStackTrace(); } return null; }}
關(guān)鍵詞:授權(quán)
客戶&案例
營(yíng)銷資訊
關(guān)于我們
客戶&案例
營(yíng)銷資訊
關(guān)于我們
微信公眾號(hào)
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。