微信公众号自动登录

微信平台地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

注意code是在前端获取。用js直接获取到。这里有一个授权问题,如果不需要用户授权 那么只能获取到openid。如果想获取其他的用户信息,就需要用户授权。

网页获取授权登录跟在小程序里面获取的是不一样的api接口。网页无法获取到小程序里面的openid,只能通过授权活到到同一个主体的unionid。

1:获取Code

获取Code一般都是全端用js去获取。当然这里需要用到 appid。并且需要记住:这里的appid跟后面拿到code之后去获取access_token,openid  用到的code 必须是一致,否则就会提示code无效,

另外:通过网页获取openid只能通过公众号的方式获取openid,如果用户在登录的时候 绑定的openid是小程序的openid,那么这里的openid是不一样的,

(微信平台里面 公众号跟小程序的openid是不一致,但是unionid是一致的,在相同的主体下,主体就是指同一个公司下面,申请账号的时候需要有公司信息)

所以需要用到unionid去做联合登录,在用户绑定的时候就需要用unionid去绑定会员信息。

前端获取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参数对应的授权作用域权限。

获取code的微信平台地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

2:通过code获取openid,这个无法获取到unionid。需要注意:这里的AppId必须跟上面获取code的appid是一致的,否则获取不到信息,

/// <summary>
        ///  通过code获取openid
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string access_token(string code)
        {
            string weiPayOpenidModelJsonStr = string.Empty;
            try
            {
                string wxAppId =  ConfigurationCenterManager.Instance.WEPAY_appid;
                string wxSecret =   ConfigurationCenterManager.Instance.WEPAY_secret;
                string args = "appid=" + wxAppId + "&" + "secret=" + wxSecret + "&" + "code=" + code + "&grant_type=authorization_code";
                System.Net.WebRequest request = System.Net.WebRequest.Create("https://api.weixin.qq.com/sns/oauth2/access_token?" + args);
                request.Method = "GET";
                using (WebResponse response = request.GetResponse())
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        StreamReader reader = new System.IO.StreamReader(stream);
                        weiPayOpenidModelJsonStr = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                AppLog.Write("获取会员信息:access_token" + ex.Message, LogMessageType.Error);
            }

            return weiPayOpenidModelJsonStr;
        }

3:第三步:由于上面的 WXOpenidModel获取到的access_token的作用域是snsapi_base,获取不到unionId,

应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)

public M665WeChatGetTokenResult WeChatAccessToken()
        {
            //AppLog.Write(string.Format("调用接口WeChatAccessToken开始,参数refreshState={0}", m665.refreshState), LogMessageType.Debug);
            M665WeChatGetTokenResult respMsg = new M665WeChatGetTokenResult();
            //Stopwatch watch = new Stopwatch();
            try
            {
                //开始计时
                //watch.Start();
                //加缓存
                ICache cache = new CacheFactory().GetCache();
                string access_token = null;
                //将access_token和getTokenTime写在同一个缓存里面
                access_token = cache.Get<string>("WeChat_AccessToken");
                //cache.Remove("WeChat_AccessTokenGetTime");
                string getTokenTime = cache.Get<string>("WeChat_AccessTokenGetTime");
                if (access_token == null || m665.refreshState == "1" || DateTime.Compare(Convert.ToDateTime(getTokenTime).AddHours(1), DateTime.Now) < 0)
                {
                    //直接写方法

                    string appid = "wx330c5becf5a36a7f";

                    string secret = "fe15061bda4cac794c5c642d09065db3";
                    string postDataStr = "grant_type=client_credential" + "&appid=" + appid + "&secret=" + secret;

                    string url ="https://api.weixin.qq.com/cgi-bin/token";

                    string retString = WeChatHelper.WebRequestPostOrGet(url + "?" + postDataStr, "");
                    JavaScriptSerializer jsv = new JavaScriptSerializer();
                    respMsg = jsv.Deserialize<M665WeChatGetTokenResult>(retString);
                    //获取成功
                    if (respMsg != null)
                    {
                        if (!string.IsNullOrEmpty(respMsg.access_token))
                        {
                            //成功
                            respMsg.result = "0";
                        }
                        else
                        {
                            //失败
                            respMsg.result = "1";
                        }
                    }
                    else
                    {
                        //失败
                        respMsg.result = "1";
                    }
                    if (respMsg.result == "0")
                    {
                        //将token加入缓存
                        cache.Add<string>("WeChat_AccessToken", respMsg.access_token, TimeSpan.FromHours(2));
                        //将调用时间加入缓存
                        cache.Add<string>("WeChat_AccessTokenGetTime", DateTime.Now.ToString(), TimeSpan.FromHours(2));
                    }
                }
                else
                {
                    respMsg.access_token = access_token;
                    respMsg.result = "0";
                    respMsg.expires_in = "7200";
                }
                //结束计时
                //watch.Stop();
                //AppLog.Write(string.Format("调用接口WeChatAccessToken结束,用时:{0}毫秒。", watch.ElapsedMilliseconds), LogMessageType.Debug);
                return respMsg;

            }
            catch (Exception ex)
            {
                AppLog.Write(string.Format("调用接口WeChatAccessToken异常"), LogMessageType.Error, ex);
                respMsg.result = "1";
                return respMsg;
            }
        }

下面是一个post方法,其实跟本次讲解的流程无关,只是通过ulr调用微信平台地址返回的数据, 

    /// <summary>
        /// Post/get 提交调用抓取
        /// </summary>
        /// <param name="url">提交地址</param>
        /// <param name="param">参数</param>
        /// <returns>string</returns>
        public static string WebRequestPostOrGet(string sUrl, string sParam)
        {
            byte[] bt = System.Text.Encoding.UTF8.GetBytes(sParam);

            Uri uriurl = new Uri(sUrl);
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uriurl);//HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url + (url.IndexOf("?") > -1 ? "" : "?") + param);
            req.Method = "Post";
            req.Timeout = 120 * 1000;
            req.ContentType = "application/x-www-form-urlencoded;";
            req.ContentLength = bt.Length;

            using (Stream reqStream = req.GetRequestStream())//using 使用可以释放using段内的内存
            {
                reqStream.Write(bt, 0, bt.Length);
                reqStream.Flush();
            }
            try
            {
                using (WebResponse res = req.GetResponse())
                {
                    //在这里对接收到的页面内容进行处理 

                    Stream resStream = res.GetResponseStream();

                    StreamReader resStreamReader = new StreamReader(resStream, System.Text.Encoding.UTF8);

                    string resLine;

                    System.Text.StringBuilder resStringBuilder = new System.Text.StringBuilder();

                    while ((resLine = resStreamReader.ReadLine()) != null)
                    {
                        resStringBuilder.Append(resLine + System.Environment.NewLine);
                    }

                    resStream.Close();
                    resStreamReader.Close();

                    return resStringBuilder.ToString();
                }
            }
            catch (Exception ex)
            {
                //return ex.Message;//url错误时候回报错
                AppLog.Write(string.Format("调用接口WebRequestPostOrGet异常,参数sUrl={0}&sParam={1}&error={2}", sUrl, sParam), LogMessageType.Error, ex);
                throw;
            }
        }

 //第四步: 根据openid与access_token 获取unionid


        /// <summary>
        /// 获取unionid
        /// </summary>
        /// <param name="access_token"></param>
        /// <param name="openid"></param>
        /// <returns></returns>
        public static string Get_unionid(string access_token, string openid)
        {
            string weixinUserInfo = string.Empty;
            try
            {
                string key = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", access_token, openid);
                WebRequest requestUserInfo = System.Net.WebRequest.Create(key);
                WebResponse responseUser = requestUserInfo.GetResponse();

                weixinUserInfo = new StreamReader(responseUser.GetResponseStream()).ReadToEnd();
                AppLog.Write("Get_unionid(unionid)返回信息:" + weixinUserInfo, LogMessageType.Info);

            }
            catch (Exception ex)
            {
                AppLog.Write("获取会员信息:Get_unionid" + ex.Message, LogMessageType.Error);
            }
            return weixinUserInfo;
        }

  //第五步:根据获取的openid 与 unionid值,获取用户信息

就是用户之前绑定的用户信息表中去查询,一般有一张表,关联用户账号或者手机号码,有 openid  跟unionid信息。直接查询到用户信息即可。

第六步:

总结前面的业务,对外的api接口如下:

/// <summary>
        ///1.1    根据微信Code自动登录 获取会员信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("WXAouthLogin")]
        public IActionResult WXAouthLogin([FromQuery] MessageRequst requst)
        {

            ResultResponse baseResult = new ResultResponse();
            try
            {
                if (string.IsNullOrEmpty(requst.Code))
                {
                    return Json(new { Result = false, Message = "参数不能为空!" });
                }
                //第一步 :根据Code 获取到 openid
                string weiPayOpenidModelJsonStr = OAuthInfo.access_token(requst.Code);
                AppLog.Write("微信服务号授权登录通过Code获取access_token返回信息:" + weiPayOpenidModelJsonStr, LogMessageType.Info);
                WXOpenidModel resultModel = JsonConvert.DeserializeObject<WXOpenidModel>(weiPayOpenidModelJsonStr);

                //第二步: WXOpenidModel获取到的access_token的作用域是snsapi_base,获取不到unionId
                // 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
                // 根据获取的openid获取unionId
                // 从接口获取
                M665WeChatGetTokenResult result = OAuthInfo.GetWeChatAccessToken().Result;
                AppLog.Write("接口返回的access_token" + JsonConvert.SerializeObject(result), LogMessageType.Info);

                if (result == null)
                {
                    AppLog.Write(String.Format("获取微信access_token错误"), LogMessageType.Info);
                    return Json(new { Result = false, Message = "获取access_token失败!" });
                }
                //第三步: 根据openid与access_token 获取unionid
                string weixinUserInfo = OAuthInfo.Get_unionid(result.access_token, resultModel.openid);
                AppLog.Write("WXAouthLogin微信服务号获取用户信息(unionid)返回信息:" + weixinUserInfo, LogMessageType.Info);
                WXUserInfoModel wXUserInfo = JsonConvert.DeserializeObject<WXUserInfoModel>(weixinUserInfo);

                //第四步:根据获取的openid 与 unionid值,获取用户信息
                UserInfoSmall uis = OAuthInfo.GetUserByWXOpenid(resultModel.openid, wXUserInfo.unionid);
                if (uis == null)
                {
                    return Json(new { Result = false, Message = "微信未绑定" });
                }
                else
                {
                    return Json(new { Result = true, Data = uis });
                }

            }
            catch (Exception ex)
            {
                baseResult.State = false;
                baseResult.Message = ex.Message;
            }
            AppLog.Write("获取会员信息:WXAouthLogin" + baseResult.Message, LogMessageType.Error);
            return Json(baseResult);
        }
    }

猜你喜欢

转载自blog.csdn.net/xulong5000/article/details/113981323