最新消息: 新版网站上线了!!!

微信公众号 网页授权登录及code been used解决详解

Ê×ÏÈ΢ÐŹ«Öںſª·¢ÍøÒ³ÊÚȨµÇ¼ʹÓû·¾³£º

¿ª·¢¹¤¾ß£ºeclipse£»·þÎñÆ÷£ºtomcat8£¬¿ª·¢ÓïÑÔ£ºJAVA¡£

ÎÒдµÄÍøÒ³ÊÚȨµÇ¼ʱÓÿª·¢Õßģʽ×Ô¶¨ÒåviewÀàÐÍ°´Å¥µã»÷ÌøתÁ´½ÓµÄ¡£

΢ÐÅÍøÒ³ÊÚȨµÇ¼Ê×ÏÈÒÔ¹Ù·½Î¢ÐÅ¿ª·¢ÎĵµÎª×¼£¬´óÌå¹²·ÖΪ4²½£º

ÏÈ˵µÚÒ»²½»ñÈ¡code£º

code˵Ã÷£ºcode×÷Ϊ»»È¡access_tokenµÄƱ¾Ý£¬Ã¿´ÎÓû§ÊÚȨ´øÉϵÄcode½«²»Ò»Ñù£¬codeÖ»ÄÜʹÓÃÒ»´Î£¬5’YÕâδ±»Ê¹ÓÃ×Ô¶¯¹ýÆÚ¡£

΢ÐŹ«ÖÚ¿ª·¢Îĵµ¸øµÄÓлñÈ¡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²ÎÊý£¬Çë×¢Òâ¿´¹ÙÍøÉϸø³öµÄdemo£º

Çë×¢Òâ΢ÐÅÊÚȨµÇ¼scopeÁ½ÖÖredirect_urlºóÃæ¸úµÄÁ´½ÓʹÓõÄЭÒé¡£

Õâ¸öЭÒéʹÓò»µ±¿ÉÄÜ»áÔÚÏîÄ¿²¿Êðµ½·þÎñÆ÷ÉϲâÊÔʱÔÚ°²×¿ºÍiosÉϳöÏÖÎÊÌâ¡£

ÖÁ´Ë£¬ÒÔsnsapi_baseΪscope·¢ÆðµÄÍøÒ³ÊÚȨ£¬ÊÇÓÃÀ´»ñÈ¡½øÈëÒ³ÃæµÄÓû§µÄopenidµÄ£¬²¢ÇÒÊǾ²Ä¬ÊÚȨ²¢×Ô¶¯Ìøתµ½»Øµ÷Ò³µÄ¡£Óû§¸ÐÖªµÄ¾ÍÊÇÖ±½Ó½øÈëÁ˻ص÷Ò³£¨ÍùÍùÊÇÒµÎñÒ³Ã棩£»

ÒÔsnsapi_userinfoΪscope·¢ÆðµÄÍøÒ³ÊÚȨ£¬ÊÇÓÃÀ´»ñÈ¡Óû§µÄ»ù±¾ÐÅÏ¢µÄ¡£µ«ÕâÖÖÊÚȨÐèÒªÓû§ÊÖ¶¯Í¬Ò⣬²¢ÇÒÓÉÓÚÓû§Í¬Òâ¹ý£¬ËùÒÔÎÞÐë¹Ø×¢£¬¾Í¿ÉÔÚÊÚȨºó»ñÈ¡¸ÃÓû§µÄ»ù±¾ÐÅÏ¢¡£

²ÎÊýÌæ»»Íê±ÏÈç¹ûÒÔsnsapi_userinfoΪscope·¢ÆðµÄÍøÒ³ÊÚȨ£¬ÊÇÔÚPC¶Ëµã»÷²Ëµ¥»áÌø³öÌáʾÓû§Í¬ÒâÊÚȨµÇ¼£¬Èç¹ûÓû§Î´¹Ø×¢¹«ÖÚºÅʱͬÑùÒ²»áÌáʾ£¬Ê¾ÀýÒ³Ã棺

Èç¹ûÊÇÔÚÒƶ¯¶ËÓû§¹Ø×¢Çé¿öÏÂÔò²»»á³öÏÖ´ËÒ³Ãæ¡£

Èç¹ûÓû§Í¬ÒâÊÚȨ£¬Ò³Ã潫ÌøתÖÁ redirect_uri/?code=CODE&state=STATE£¬ÈôÌøת´íÎóÇë¸ù¾ÝÈÕÖ¾Êä³öµÄ´íÎóÂëÔÚ¹ÙÍøÉϲ鿴ÏàÓ¦µÄ˵Ã÷£¬¸½ÉϹÙÍøÉÏ´íÎó·µ»ØÂë˵Ã÷£º

È»ºóÊǵڶþ²½¸ù¾ÝÁ´½Ó´«¹ýÀ´µÄcodeÈ¥»ñÈ¡ÍøÒ³ÊÚȨaccess_token£º

¹ÙÍøÉϸø³öµÄÁ´½Ó£º

Õâ¸öaccess_tokenºÍ»ù±¾µÄaccess_token²»Í¬£¬¾ßÌåÇë²Î¿¼¹ÙÍø˵Ã÷£¬ÕâÀï¸ø³ö»ñÈ¡ÍøÒ³ÊÚȨaccess_tokenµÄJAVAʵÏÖ·½·¨£º

/**
  * »ñÈ¡ÍøÒ³ÊÚȨƾ֤
  * 
  * @param appId ¹«ÖÚÕ˺ŵÄΨһ±êʶ
  * @param appSecret ¹«ÖÚÕ˺ŵÄÃÜÔ¿
  * @param code
  * @return WeixinAouth2Token
  */
 public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
  WeixinOauth2Token wat = null;
  // Æ´½ÓÇëÇóµØÖ·
  String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
  requestUrl = requestUrl.replace("APPID", appId);
  requestUrl = requestUrl.replace("SECRET", appSecret);
  requestUrl = requestUrl.replace("CODE", code);
  // »ñÈ¡ÍøÒ³ÊÚȨƾ֤
  JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
  if (null != jsonObject) {
   try {
    wat = new WeixinOauth2Token();
    wat.setAccessToken(jsonObject.getString("access_token"));
    wat.setExpiresIn(jsonObject.getInt("expires_in"));
    wat.setRefreshToken(jsonObject.getString("refresh_token"));
    wat.setOpenId(jsonObject.getString("openid"));
    wat.setScope(jsonObject.getString("scope"));
   } catch (Exception e) {
    wat = null;
    int errorCode = jsonObject.getInt("errcode");
    String errorMsg = jsonObject.getString("errmsg");
    log.error("»ñÈ¡ÍøÒ³ÊÚȨƾ֤ʧ°Ü errcode:{} errmsg:{}", errorCode, errorMsg);
   }
  }
  return wat;
 }

ÐèÒªµÄ²ÎÊýΪ¿ª·¢ÕßID(AppID)£¬¿ª·¢ÕßÃÜÂë(AppSecret)£¬ºÍ»ñÈ¡µ½µÄcode¡£ÕýÈ··µ»ØjsonÊý¾Ý°üΪ£º

È»ºóµÚÈý²½£¬Èç¹ûÐèÒªµÄ»°½øÐУ¬·½·¨ºÍµÚ¶þ²½ÀàËÆ£¬ËùÐèÁ´½Ó¹ÙÍø¸øµÄÓС£

×îºóÒ»²½ÊÇ»ñÈ¡Óû§µÄÐÅÏ¢(ÐèÒªscopeΪsnsapi_userinfo,snsapi_baseÖ»ÄÜ»ñÈ¡µ½Óû§µÄopenId)£º

ËùÐèÒªµÄÇëÇó·½·¨£º

È»ºóÌæ»»³ÉÏàÓ¦µÄ²ÎÊý£¬JAVA´úÂëΪ:

/**
  * ͨ¹ýÍøÒ³ÊÚȨ»ñÈ¡Óû§ÐÅÏ¢
  * 
  * @param accessToken ÍøÒ³ÊÚȨ½Ó¿Úµ÷ÓÃƾ֤
  * @param openId Óû§±êʶ
  * @return SNSUserInfo
  */
 public static SNSUserInfo getSNSUserInfo(String accessToken, String openId) {
  SNSUserInfo snsUserInfo = null;
  // Æ´½ÓÇëÇóµØÖ·
  String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID〈=zh_CN";
  requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
  // ͨ¹ýÍøÒ³ÊÚȨ»ñÈ¡Óû§ÐÅÏ¢
  JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);

  if (null != jsonObject) {
   try {
    snsUserInfo = new SNSUserInfo();
    // Óû§µÄ±êʶ
    snsUserInfo.setOpenId(jsonObject.getString("openid"));
    // êdzÆ
    snsUserInfo.setNickname(jsonObject.getString("nickname"));
    // ÐÔ±ð£¨1ÊÇÄÐÐÔ£¬2ÊÇÅ®ÐÔ£¬0ÊÇδ֪£©
    snsUserInfo.setSex(jsonObject.getInt("sex"));
    // Óû§ËùÔÚ¹ú¼Ò
    snsUserInfo.setCountry(jsonObject.getString("country"));
    // Óû§ËùÔÚÊ¡·Ý
    snsUserInfo.setProvince(jsonObject.getString("province"));
    // Óû§ËùÔÚ³ÇÊÐ
    snsUserInfo.setCity(jsonObject.getString("city"));
    // Óû§Í·Ïñ
    snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
   } catch (Exception e) {
    snsUserInfo = null;
    int errorCode = jsonObject.getInt("errcode");
    String errorMsg = jsonObject.getString("errmsg");
    log.error("»ñÈ¡Óû§ÐÅϢʧ°Ü errcode:{} errmsg:{}", errorCode, errorMsg);
   }
  }
  return snsUserInfo;
 }

ÉÏÃæËùÊö½ÔÊǸù¾Ý΢ÐŹ«ÖںŹÙÍøÒÔ¼°°Ù¶ÈËùд¡£ÁíÍ⻹²Î¿¼Ò»ÆªºÜ²»´íµÄ΢ÐŹ«Öںſª·¢Îĵµ£¬¿ÉÒÔ˵ÊÇ´øÎÒÈëµÄÃÅ£¬¸ø¸öÁ´½Ó£º

ÏÂÃæ˵һÏÂ΢ÐÅÍøÒ³ÊÚȨµÇ¼ÖÐÓöµ½µÄcode been usedÎÊÌ⣺

ÎÒÔÚ΢ÐÅÍøÒ³ÊÚȨµÇ¼дÍêÖ®ºó¿ªÊ¼²âÊÔ£¬ÔÚ±£Ö¤´úÂëµÄÕýÈ·ÐÔÓë׼ȷÐԺ󣬴ò¿ªÎ¢ÐŹ«Öںţ¬µã»÷×Ô¼º¶¨ÒåÌøתÁ´½ÓµÄ²Ëµ¥£¬²¢³É¹¦½øÈ룬µ«ÊÇÔÚµã»÷ˢлòÕß»ØÍËÊǻᱨ´í£¬´íÎóµÄÐÅÏ¢¾ÍÊÇcode been used¡£

¹ÙÍøÉϸø³öµÄ˵Ã÷ºÜÏêϸ£¬codeÖ»Äܱ»Ê¹ÓÃÒ»´Î£¬Èç¹ûÏÔʾcode been usedÔò˵Ã÷code±»Öظ´Ê¹ÓÃÁË¡£

Ê×ÏÈ˵һ¸ö¼òµ¥µÄcode been used´íÎóµÄ²úÉú£º

ÓеĿª·¢ÕßÔÚдÍøÒ³ÊÚȨµÇ¼ʱ»á³öÏÖÕâÑùµÄÒ³Ã棺

ÕâÊÇÔÚ΢ÐÅ¿ª·¢¹«ÖÚºÅÉÏûÓÐÅäÖð²È«ÓòÃû£¬µ¼ÖÂ΢ÐÅÍøÒ³ÊÚȨµÇ¼ʱ»áÏÔʾÕâÑùµÄÒ³Ã棬urlÌøתÁËÁ½´Î£¬´«ÈëµÄcode±»Öظ´Ê¹ÓÃÁË£¬Óöµ½ÕâÖֵĿÉÒÔÏÖÔÚ΢ÐÅ¿ª·¢¹«ÖÚºÅÀïÃæÅäÖð²È«ÓòÃû¡£

È»ºó˵ÆÕ±éÓöµ½µÄcode been usedÎÊÌâ¡£

»ù±¾Ë¼Â·Ê±£ºµ±ÎÒµã»÷²Ëµ¥°´Å¥½øÈëÒ³Ãæʱ£¬ÏÈÈ¥sssion»º´æÖÐÈ¥ÄÇÓÉcode»ñÈ¡µ½µÄopenId£¬Èç¹ûopenId²»´æÔÚ£¬ÔòÖ¤Ã÷codeΪÊ×´ÎʹÓ㬿ÉÒÔ¸ù¾Ý´«¹ýÀ´µÄcode»ñÈ¡ÏàÓ¦µÄaccess_tokenºÍopenId¡£

Èç¹û´æÔÚ£¬ÔòÖ±½ÓʹÓûñÈ¡µ½µÄopenIdÈ¥»ñÈ¡Óû§µÄһϵÁÐÐÅÏ¢¡£

ÎÒÓõÄʱspringMVC£¬¼òµ¥ÊµÏÖ´úÂëΪ£º

Ê×ÏÈÔÚ¿ª·¢Õ߶¨ÒåµÄ²Ëµ¥Â·¾¶ÉÏÅäÖÃÓòÃûºÍÌøתµÄ¿ØÖÆÆ÷·½·¨£º

Ç°ÃæÄ£ºýµÄÊÇ×Ô¼ºÅäÖõÄÓòÃû£¬ºóÃæ/weixin/redirectÔòÊÇÒªÌøתµÄ·½·¨¡£

Ìøתµ½µÄ·½·¨Îª£º

JAVA´úÂ룺

/**»ñÈ¡Óû§openId
  * @throws IOException */
 @RequestMapping(value = "/redirect", method = RequestMethod.GET)
 public ModelAndView repairs(ModelAndView mav, HttpServletRequest request, HttpServletResponse resp) throws IOException{
  String openId = (String) request.getSession().getAttribute("openId");//ÏÈ´Ó»º´æÖлñȡͨ¹ýcodeµÃµ½µÄopenID
  System.out.println(openId);//²âÊÔÊä³öopenId
  if(openId==null){//ÅжÏopenIdÊÇ·ñΪ¿Õ(ÅжÏcodeÊÇ·ñΪµÚÒ»´Î±»Ê¹ÓÃ)
   RedirectUtils.redireUrl1(request, resp);//openidΪ¿ÕÒ²¾ÍÊÇcode±»µÚÒ»´ÎʹÓÃʱÌøת·½·¨
    return null;
  }
   mav.addObject("openId",openId);//ûÓб»Ê¹ÓÃʱ
   mav.setViewName("/weixin/repairs");//·µ»ØÒªÌøתµÄÊÓͼҳÃæ
  return mav;
 }

RedirectUtils.redireUrl1(request, resp);ΪÖض¨ÏòÌøתµÄ·¾¶¡£JAVA´úÂ룺

public static void redireUrl1(HttpServletRequest request,HttpServletResponse response){
  System.out.println("Ìøת");//²âÊÔÊÇ·ñÌøת¹ýÀ´ÁË
  String a="";
  if(request.getQueryString()!=null){
   a="?"+request.getQueryString();
  }
  String url = Base64.getBase64(request.getRequestURL()+a);//´ËΪÁ´½ÓÖдøµÄһЩ²ÎÊý ²»ÐèÒª¿ÉÒÔ²»ÓÃд
  System.out.println(request.getRequestURL()+a);
   String basePath = WeChatConfig.URL+"weixin/wxyz?url="+url;//redirect_uriµØÖ· 
   System.out.println(basePath);
   String urls="https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.APP_ID+
     "&redirect_uri=" + CommonUtil.urlEncodeUTF8(basePath)+
     "&response_type=code" +
     "&scope=snsapi_userinfo" +
     "&state=STATE#wechat_redirect";
   try {
    response.sendRedirect(urls);//Öض¨ÏòÖ´ÐÐurl
   }catch(Exception e){
    e.printStackTrace();
   }
 }

ÆäÖÐBase64.getBase64ΪBase64¼ÓÃÜ·½·¨£¬WeChatConfig.URLΪÄã×Ô¼ºÎ¢ÐŹ«ÖÚƽ̨ÅäÖõݲȫÓòÃû£¬CommUtil.urlEncodeUTF8¶ÔÖض¨ÏòÁ´½Ó½øÐбàÂë¡£

ÌṩһÏÂBase64·½·¨ÖеļÓÃܽâÃÜ·½·¨£¬ÇëÏÈÏÂÔØÏàÓ¦µÄjar°ü£º

**
 * Base64¹¤¾ß CREATE 2016.12.14 form yjf
 * 
 */
public class Base64 {
 /**
  * Base64¼ÓÃÜ
  * 
  */
 @SuppressWarnings("restriction")
 public static String getBase64(String value) {
  byte[] bytes = null;
  String basevalue = null;
  try {
   bytes = value.getBytes("utf-8");
  } catch (UnsupportedEncodingException e) {
   e.printStackTrace();
  }
  if (bytes != null) {
   basevalue = new BASE64Encoder().encode(bytes);
  }
  return basevalue;
 }

 /**
  * Base64½âÃÜ
  * 
  */
 @SuppressWarnings("restriction")
 public static String getFromBase64(String basevalue) {
  byte[] bytes = null;
  String result = null;
  if (basevalue != null) {
   BASE64Decoder decoder = new BASE64Decoder();
   try {
    bytes = decoder.decodeBuffer(basevalue);
    result = new String(bytes, "utf-8");
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  return result;
 }

}

È»ºóʱCommUtil.urlEncodeUTF8±àÂë´úÂ룺

/**
  * URL±àÂ루utf-8£©
  * 
  * @param source
  * @return
  */
 public static String urlEncodeUTF8(String source) {
  String result = source;
  try {
   result = java.net.URLEncoder.encode(source, "utf-8");
  } catch (UnsupportedEncodingException e) {
   e.printStackTrace();
  }
  return result;
 }

È»ºó·½·¨Ö´ÐÐresponse.sendRedirect(urls);Ìøת»Øwxyz·½·¨½øÐлñȡһϵÁвÎÊý£¬´úÂëΪ£º

@RequestMapping(value="/wxyz",method=RequestMethod.GET)
 public ModelAndView wxYz(ModelAndView mvc,HttpServletRequest req,HttpServletResponse response){
   System.out.println("΢ÐÅÑéÖ¤");//²âÊÔÊÇ·ñÌøתµ½´Ë·½·¨ÖÐ
   String code=req.getParameter("code");//»ñÈ¡url²ÎÊýÖеÄcode
   WeixinOauth2Token weixinOauth2Token = AdvancedUtil.getOauth2AccessToken(WeChatConfig.APP_ID, WeChatConfig.APP_SECRET, code);
   if(weixinOauth2Token.getOpenId()!=null){
    String openId = weixinOauth2Token.getOpenId();
    req.getSession().setAttribute("openId",openId);//½«»ñÈ¡µ½µÄopenID´æÈësession»º´æÖÐ
    System.out.println("openId"+openId);
    mvc.addObject("openId",openId);
    mvc.setViewName("redirect:/weixin/wxLogin");
    return mvc;
   }
   return null;
 }

ÆäÖÐAdvancedUtil.getOauth2AccessToken·½·¨Ê±»ñÈ¡ÍøÒ³ÊÚȨaccess_token ·½·¨£¬´úÂëΪ£º

/**
  * »ñÈ¡ÍøÒ³ÊÚȨƾ֤
  * 
  * @param appId ¹«ÖÚÕ˺ŵÄΨһ±êʶ
  * @param appSecret ¹«ÖÚÕ˺ŵÄÃÜÔ¿
  * @param code
  * @return WeixinAouth2Token
  */
 public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
  WeixinOauth2Token wat = null;
  // Æ´½ÓÇëÇóµØÖ·
  String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
  requestUrl = requestUrl.replace("APPID", appId);
  requestUrl = requestUrl.replace("SECRET", appSecret);
  requestUrl = requestUrl.replace("CODE", code);
  // »ñÈ¡ÍøÒ³ÊÚȨƾ֤
  JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
  if (null != jsonObject) {
   try {
    wat = new WeixinOauth2Token();
    wat.setAccessToken(jsonObject.getString("access_token"));
    wat.setExpiresIn(jsonObject.getInt("expires_in"));
    wat.setRefreshToken(jsonObject.getString("refresh_token"));
    wat.setOpenId(jsonObject.getString("openid"));
    wat.setScope(jsonObject.getString("scope"));
   } catch (Exception e) {
    wat = null;
    int errorCode = jsonObject.getInt("errcode");
    String errorMsg = jsonObject.getString("errmsg");
    log.error("»ñÈ¡ÍøÒ³ÊÚȨƾ֤ʧ°Ü errcode:{} errmsg:{}", errorCode, errorMsg);
   }
  }
  return wat;
 }

ʹÓô˷½·¨Ìæ»»ÉÏÏàÓ¦µÄ²ÎÊý¼´¿É¡£ÒòΪ΢ÐÅÊÚȨµÇ¼»áÌøתÁ½´ÎÁ´½Ó£¬ËùÒÔµ±»ñÈ¡³É¹¦ÔòÌøתµ½wxLogin·½·¨ÖнøÐÐÑéÖ¤£º

String bassPath1 = WeChatConfig.URL+"weixin/wxyz";//¶¨ÒåµÄ·¾¶
 @RequestMapping(value="wxLogin1",method=RequestMethod.GET)
 public ModelAndView wxLogin(HttpServletRequest request,HttpServletResponse response){
  String openId = (String) request.getSession().getAttribute("openId");//ÏÈ´Ó»º´æÖÐÈ¥ÄÃopenId
  
  if(openId==null){//Èç¹ûûÓеĻ°
   String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.APP_ID +
      "&redirect_uri=" + CommonUtil.urlEncodeUTF8(bassPath1)+
      "&response_type=code" +
      "&scope=snsapi_userinfo" +
      "&state=STATE#wechat_redirect";
   try {
    response.sendRedirect(url);
   } catch (IOException e) {
    e.printStackTrace();
   }
    
  }else{
   
   return new ModelAndView("weixin/repairs");//·µ»ØÒ³Ãæ
  }
  return null;
 }

ÖÁ´Ë£¬´ò¿ªËùÐèÒªµÄÒ³Ã棬ÎÞÂÛʱµÚÒ»´Î½øÈ뻹ÊÇˢР¶¼²»»á³öÏÖcode been usedÕâÖÖÇé¿öÁË£¬ÖÁÉÙ±¾È˲âÊÔûÓгöÏÖ¹ý¡£

ÒÔÉϾÍÊDZ¾ÎĵÄÈ«²¿ÄÚÈÝ£¬Ï£Íû¶Ô´ó¼ÒµÄѧϰÓÐËù°ïÖú£¬Ò²Ï£Íû´ó¼Ò¶à¶àÖ§³Ö½Å±¾Ö®¼Ò¡£

转载请注明:谷谷点程序 » 微信公众号 网页授权登录及code been used解决详解