• C#微信公众号开发 -- (七)自定义菜单事件之VIEW及网页(OAuth2.0)授权


    通俗来讲VIEW其实就是我们在C#中常用的a标签,可以直接在自定义菜单URL的属性里面写上需要跳转的链接,也即为单纯的跳转。

    但更多的情况下,我们是想通过VIEW来进入指定的页面并进行操作。

    举一个简单的例子,假如我们的后台需要记录有哪些用户在什么时间访问了哪个网页,那么这就需要当用户点击VIEW的时候我们程序记录

    所以微信官方提供了一个很好的解决方案,那就是将VIEW与网页授权获取用户信息相结合来实现

    我们以建好的自定义菜单中的"搜索"VIEW为例,来简单的时候上面的操作。

    首先将自定义菜单重新URL重新重新写入网页授权的链接,以及新建一个网页授权的页面OAuthRedirectUrl.aspx。

    {
         "button":[
         {    
              "type":"click",
              "name":"今日歌曲",
              "key":"V1001_TODAY_MUSIC"
          },
          {
               "type":"click",
               "name":"歌手简介",
               "key":"V1001_TODAY_SINGER"
          },
          {
               "name":"菜单",
               "sub_button":[
               {    
                   "type":"view",
                   "name":"搜索",
                   "url":"https://open.weixin.qq.com/connect/oauth2/authorize?appid=你的微信公众号appid&redirect_uri=http://xxx.com/WeiXin/OAuthRedirectUrl.aspx?reurl=so&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
                },
                {
                   "type":"view",
                   "name":"视频",
                   "url":"http://v.qq.com/"
                },
                {
                   "type":"click",
                   "name":"赞一下我们",
                   "key":"V1001_GOOD"
                }]
           }]
     }

    来看一下微信官方对这一串URL的参数解释:

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

    其中参数redirect_uri也就是上面提到新建的页面OAuthRedirectUrl.aspx,也就是说在跳转到想要的页面之前,先要到OAuthRedirectUrl.aspx去进行授权并获取用户基本信息,从而供自己使用。

    OAuthRedirectUrl.aspx要做的操作其实也是很简单,完成微信指定的授权。

    private string _appid = "你的微信公众号appid";
            private string _appsecret = "你的微信公众号appsecret";
            private string reurl = "";
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    //获取传过来的值
                    if (Request.QueryString["reurl"] != null && Request.QueryString["reurl"].ToString() != "")
                    {
                        reurl = Request.QueryString["reurl"].ToString();
                    }
                    string code = "";
                    if (Request.QueryString["code"] != null && Request.QueryString["code"] != "")
                    {
                        code = Request.QueryString["code"].ToString();
                        OAuth_Token Model = Get_token(code);
                        OAuthUser OAuthUser_Model = Get_UserInfo(Model.access_token, Model.openid);
                        //"http://xx.com/" + reurl + ".aspx?openid=" + OAuthUser_Model.openid;
                        string strurl = "";
                        switch (reurl)
                        {
                            case "so":
                                strurl = "http://www.cnblogs.com/HappyAnt/";
                                break;
                        }
    
                        Response.Redirect(strurl);
                        //Response.Write("reurl:" + reurl + ",code:" + code + ",openid:" + OAuthUser_Model.openid);
                    }
                }
            }
    
            //获得Token
            protected OAuth_Token Get_token(string Code)
            {
                string Str = GetJson("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + _appid + "&secret=" + _appsecret + "&code=" + Code + "&grant_type=authorization_code");
                OAuth_Token Oauth_Token_Model = JsonHelper.ParseFromJson<OAuth_Token>(Str);
                return Oauth_Token_Model;
            }
            //刷新Token
            protected OAuth_Token refresh_token(string REFRESH_TOKEN)
            {
                string Str = GetJson("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + _appid + "&grant_type=refresh_token&refresh_token=" + REFRESH_TOKEN);
                OAuth_Token Oauth_Token_Model = JsonHelper.ParseFromJson<OAuth_Token>(Str);
                return Oauth_Token_Model;
            }
            //获得用户信息
            protected OAuthUser Get_UserInfo(string REFRESH_TOKEN, string OPENID)
            {
                // Response.Write("获得用户信息REFRESH_TOKEN:" + REFRESH_TOKEN + "||OPENID:" + OPENID);
                string Str = GetJson("https://api.weixin.qq.com/sns/userinfo?access_token=" + REFRESH_TOKEN + "&openid=" + OPENID);
                OAuthUser OAuthUser_Model = JsonHelper.ParseFromJson<OAuthUser>(Str);
                return OAuthUser_Model;
            }
            protected string GetJson(string url)
            {
                WebClient wc = new WebClient();
                wc.Credentials = CredentialCache.DefaultCredentials;
                wc.Encoding = Encoding.UTF8;
                string returnText = wc.DownloadString(url);
    
                if (returnText.Contains("errcode"))
                {
                    //可能发生错误
                }
                //Response.Write(returnText);
                return returnText;
            }
        }
    
        
    
        public class OAuth_Token
        {
            public OAuth_Token()
            {
                //
                //TODO: 在此处添加构造函数逻辑
                //
            }
            //access_token    网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
            //expires_in    access_token接口调用凭证超时时间,单位(秒)
            //refresh_token    用户刷新access_token
            //openid    用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
            //scope    用户授权的作用域,使用逗号(,)分隔
            public string access_token { get; set; }
            public string expires_in { get; set; }
            public string refresh_token { get; set; }
            public string openid { get; set; }
            public string scope { get; set; }
        }
    
        public class OAuthUser
        {
            public OAuthUser()
            { }
            #region 数据库字段
            private string _openID;
            private string _searchText;
            private string _nickname;
            private string _sex;
            private string _province;
            private string _city;
            private string _country;
            private string _headimgUrl;
            private string _privilege;
            #endregion
    
            #region 字段属性
            /// <summary>
            /// 用户的唯一标识
            /// </summary>
            public string openid
            {
                set { _openID = value; }
                get { return _openID; }
            }
            /// <summary>
            /// 
            /// </summary>
            public string SearchText
            {
                set { _searchText = value; }
                get { return _searchText; }
            }
            /// <summary>
            /// 用户昵称 
            /// </summary>
            public string nickname
            {
                set { _nickname = value; }
                get { return _nickname; }
            }
            /// <summary>
            /// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 
            /// </summary>
            public string sex
            {
                set { _sex = value; }
                get { return _sex; }
            }
            /// <summary>
            /// 用户个人资料填写的省份
            /// </summary>
            public string province
            {
                set { _province = value; }
                get { return _province; }
            }
            /// <summary>
            /// 普通用户个人资料填写的城市 
            /// </summary>
            public string city
            {
                set { _city = value; }
                get { return _city; }
            }
            /// <summary>
            /// 国家,如中国为CN 
            /// </summary>
            public string country
            {
                set { _country = value; }
                get { return _country; }
            }
            /// <summary>
            /// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
            /// </summary>
            public string headimgurl
            {
                set { _headimgUrl = value; }
                get { return _headimgUrl; }
            }
            /// <summary>
            /// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)其实这个格式称不上JSON,只是个单纯数组
            /// </summary>
            public string privilege
            {
                set { _privilege = value; }
                get { return _privilege; }
            }
            #endregion
        }

    要点:

    1:页面上面必须要有接受code的代码,因为code要换取一个特殊的网页授权access_token

    2:C#微信公众号开发 -- (四)获取API调用所需的全局唯一票据access_token 与这次的网页授权access_token不是一个值,也不是一个概念。

    3:在页面中需要生成OAuth_Token,OAuthUser两个类,与微信提供的字段要完全吻合(更好的方式是让这两个类进行封装)

    4:strurl中还可以写上带参数的链接,想获取的客户信息只需要在OAuthUser_Model读取就好了

    5:一般的程序开发还暂时用不到“刷新Token”的方法,反正我现在是一直没用到,这里作为了解就好了

    6:如果你这些都配置好后,页面却显示 ”redirect_uri 参数错误” ,那么请注意读微信的开发说明 

    “在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的开发者中心页配置授权回调域名”

    以及检查你的URL链接里面参数有没有错误,参数顺序有没有错误。

    做完这些工作以后,就可以真正意义上的实现跳转了,也即实现了VIEW它本身应有的价值。
  • 相关阅读:
    Mac下ssh连接远程服务器时自动断开问题
    解决php中json_decode的异常JSON_ERROR_CTRL_CHAR (json_last_error = 3)
    如何写.gitignore只包含指定的文件扩展名
    python操作mysql数据库
    php数组函数
    Python中字符串切片操作
    Python实现字符串反转的几种方法
    每个Android开发者都应该了解的资源列表
    Android Studio 入门指南
    一个优秀的Android应用从建项目开始
  • 原文地址:https://www.cnblogs.com/Violety/p/9814698.html
Copyright © 2020-2023  润新知