C#微信公众平台开发一网页授权

 

C#微信公众平台开发一网页授权

在开发公众号时经常会遇到有些功能需要用户登录后才能使用,我们自己编写的程序或许有自带登录页面,但用户每次都要输入账号密码很是麻烦,所以考虑能否用微信账号授权登录,这样只要授权过了,除非授权过期,否则都不需要重新登录,接下来我们来研究如何完成授权操作。

一、为了实现网页授权功能,需要解决的问题

1、微信网页授权是通过在微信客户端调用授权接口,用户同意授权后微信调用我们指定的回调函数进行后续业务操作,在这里比较特殊的是回调函数必须是在某个域名下,所以开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。

 

2、通过开发者ID及密码调用获取access_token接口时,需要设置访问来源IP(上述域名所在服务器的外网IP地址)为白名单,可在 开发 -> 基本配置 -> 公众号开发信息 -> IP白名单 进行设置。

 

二、实现步骤

1 第一步:用户同意授权,获取code

在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面,可以通过微信客户端打开或使用微信web开发者工具打开:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问

参考实例(微信web开发者工具

 

参数说明

参数是否必须说明
appid 公众号的唯一标识(可以点开 开发-> 基本配置 查看)
redirect_uri 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理(前面已经说过,我们的回调函数需部署到域名下,这里的地址就回调函数的地址)
response_type 返回类型,请填写code
scope 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect 无论直接打开还是做页面302重定向时候,必须带此参数

 

2 第二步:通过code换取网页授权access_token

HttpWebRequest 请求方法
        /// <summary>
        /// postweb请求
        /// </summary>
        /// <param name="postUrl"></param>
        /// <param name="paramData"></param>
        /// <param name="dataEncode"></param>
        /// <returns></returns>
        public static string PostWebRequest(string postUrl, string paramData)
        {
            string ret = string.Empty;
            try
            {
                byte[] byteArray = Encoding.UTF8.GetBytes(paramData);
                HttpWebRequest webReq = WebRequest.Create(postUrl) as HttpWebRequest;
                webReq.Method = "GET";
                HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                ret = sr.ReadToEnd();
                sr.Close();
                response.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return ret;
        }    

 

调用微信接口获取access_token信息

        public Dictionary<string, object> get_access_token(string code)
        {
            JavaScriptSerializer Jss = new JavaScriptSerializer();
            string url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", "AppID", "AppSecret", code);
            Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(PostWebRequest(url, ""));
            return respDic;
        }

3 第三步:刷新access_token(如果需要)

由于access_token有,涉及access_token的获取access_token的接口是有次数限制的,所以我推荐大家做一个全局变量存储,定时刷新,请参考《C#微信公众平台开发—access_token的获取存储与更新》

 

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

根据第二步获取到的access_token调用微信接口获取用户信息

        /// <summary>
        /// 用openid换取用户信息
        /// </summary>
        /// <param name="openid">微信标识id</param>
        /// <returns></returns>
        public Dictionary<string, object> GetUserInfo(string code)
        {
            JavaScriptSerializer Jss = new JavaScriptSerializer();
            Dictionary<string, object> access_info = get_access_token(code);//获取access_token
            string url = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN", access_info["access_token"], access_info["openid"]);
            Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(PostWebRequest(url, ""));
            return respDic;
        }

 

5 第五步:将上述获取的用户信息展示到客户端上

在授权回调函数中完成相关业务

        /// <summary>
        /// 授权回调函数
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            try
            {
                var code = Request.QueryString["code"];  //获取回调返回的code
                if (!string.IsNullOrEmpty(code))
                {
                    Dictionary<string, object> DicJson = GetUserInfo(code.ToString());  //获取用户信息
                    ViewBag.nickname = DicJson["nickname"];
                    ViewBag.openid = DicJson["openid"];
                    ViewBag.province = DicJson["province"];
                    ViewBag.city = DicJson["city"];
                    ViewBag.country = DicJson["country"];
                    switch (DicJson["sex"].ToString())
                    {
                        case "1":ViewBag.sex = "";break;
                        case "2": ViewBag.sex = ""; break;
                        default: ViewBag.sex = "未知"; break;
                    }
                    ViewBag.Error = "获取用户信息成功";
                }
                else
                {
                    ViewBag.nickname = "";
                    ViewBag.openid = "";
                    ViewBag.province = "";
                    ViewBag.city = "";
                    ViewBag.unionid = "";
                    ViewBag.code = "";
                    ViewBag.Error = "code没找到!";
                }
            }
            catch (Exception ex)
            {
                ViewBag.nickname = "";
                ViewBag.openid = "";
                ViewBag.province = "";
                ViewBag.city = "";
                ViewBag.unionid = "";
                ViewBag.Error = ex.Message;
            }
            return View();
        }

前端代码参考(这里主要是为了测试,所以没有细调样式,大家凑合着看)

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>获取用户信息</h1>
</div>

<div class="row">
    <div class="col-md-4">
        <h2>用户名</h2>
        <p>@ViewBag.nickname</p>
    </div>

    <div class="col-md-4">
        <h2>OpenID</h2>
        <p>@ViewBag.openid</p>
    </div>
    <div class="col-md-4">
        <h2>性别</h2>
        <p>@ViewBag.sex</p>
    </div>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>国家</h2>
        <p>@ViewBag.country</p>
    </div>
    <div class="col-md-4">
        <h2>省份</h2>
        <p>@ViewBag.province</p>
    </div>
    <div class="col-md-4">
        <h2>城市</h2>
        <p>@ViewBag.city</p>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <h2>错误信息</h2>
        <p>@ViewBag.Error</p>
    </div>
</div>

 

posted on 2019-05-20 17:43  扯。  阅读(1920)  评论(0编辑  收藏  举报

导航