• 微信开放平台之获取用户信息的授权方式扩展


    在SENPARC底层,提供了微信用户授权验证的方式:

    在下图位置:

    namespace Senparc.Weixin.MP.Sample.Filters
    {
        /// <summary>
        /// OAuth自动验证,可以加在Action或整个Controller上
        /// </summary>
        public class CustomOAuthAttribute : SenparcOAuthAttribute
        {
            public CustomOAuthAttribute(string appId, string oauthCallbackUrl)
                : base(appId, oauthCallbackUrl)
            {
                base._appId = base._appId ?? System.Configuration.ConfigurationManager.AppSettings["TenPayV3_AppId"];
            }
    
            public override bool IsLogined(HttpContextBase httpContext)
            {
                return httpContext != null && httpContext.Session["OpenId"] != null;
    
                //也可以使用其他方法如Session验证用户登录
                //return httpContext != null && httpContext.User.Identity.IsAuthenticated;
            }
        }
    }

    在我近期的项目中进行了一些扩展:

    //-----------------------------------------------------------------------
    // <copyright file="CustomOAuthAttribute" company="FenSiShengHuo, Ltd.">
    //     Copyright (c) 2018 , All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    
    using System.Web;
    using Senparc.Weixin.MP.MvcExtension;
    using System.Web.Configuration;
    using DotNet.MVC.Infrastructure.Utilities;
    using System;
    using DotNet.WeChat.CommonService;
    
    namespace DotNet.WeChat.MVC.Filters
    {
        /// <summary>
        /// CustomOAuthAttribute
        /// 
        /// OAuth自动验证,可以加在Action或整个Controller上
        /// 
        /// 修改纪录
        /// 
        /// 2018-03-29 版本:1.0 JiShiYu 创建文件。     
        /// 
        /// <author>
        ///     <name>JiShiYu</name>
        ///     <date>2018-03-29</date>
        /// </author>
        /// </summary>
        public class CustomWechatMPOAuthAttribute : SenparcOAuthAttribute
        {
            /// <summary>
            ///  OAuth自动验证,可以加在Action或整个Controller上
            /// </summary>
            /// <param name="appId"></param>
            /// <param name="componentAppId"></param>
            /// <param name="oauthCallbackUrl"></param>
            public CustomWechatMPOAuthAttribute(string appId = null, string componentAppId = null, string oauthCallbackUrl = null)
                : base(appId, oauthCallbackUrl)
            {
                base._appId = base._appId ?? WebConfigurationManager.AppSettings["WeixinAppId"];
                base._oauthCallbackUrl = base._oauthCallbackUrl ?? "/Admin/WeChatMP/OAuthCallback";
            }
    
            public override bool IsLogined(HttpContextBase httpContext)
            {
                if (httpContext.Request.Url.Host.IndexOf("fensishenghuo.com", StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    //return httpContext != null && httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] != null;
    
                    if (httpContext != null)
                    {
                        if (httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] != null)
                        {
                            WechatUserInfo wechatUserInfo = httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] as WechatUserInfo;
                            if (wechatUserInfo != null && wechatUserInfo.MPUserInfo != null)
                            {
                                return true;
                            }
                        }
                    }
                }
                return false;
                //也可以使用其他方法如Session验证用户登录
                //return httpContext != null && httpContext.User.Identity.IsAuthenticated;
            }
        }
    }

    目前要基于开放平台进行开发,也需要获取用户的信息,开放平台获取用户返回的信息跟公众号的不一样,分别如下:

     公众号的用户:  Senparc.Weixin.MP.AdvancedAPIs.User.UserInfoJson.cs,我这里增加了  [Serializable]

    /*----------------------------------------------------------------
        Copyright (C) 2018 Senparc
    
        文件名:UserInfoJson.cs
        文件功能描述:获取用户信息返回结果
    
    
        创建标识:Senparc - 20150211
    
        修改标识:Senparc - 20150303
        修改描述:整理接口
    
        修改标识:jsionr - 20150321
        修改描述:添加remark属性
    
        修改标识:Senparc - 20150321
        修改描述:添加unionid属性
    
        修改标识:jsionr - 20150513
        修改描述:增加个人分组信息
    
        修改标识:Senparc - 20150526
        修改描述:修改备注
    
        修改标识:Senparc - 20150727
        修改描述:添加批量获取用户基本信息返回结果
    
        修改标识:Senparc - 20150727
        修改描述:添加批量获取用户基本信息返回结果
    
    ----------------------------------------------------------------*/
    
    using System;
    using System.Collections.Generic;
    using Senparc.Weixin.Entities;
    
    namespace Senparc.Weixin.MP.AdvancedAPIs.User
    {
        /// <summary>
        /// 高级接口获取的用户信息
        /// </summary>
        [Serializable]
        public class UserInfoJson : WxJsonResult
        {
            /// <summary>
            /// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
            /// </summary>
            public int subscribe { get; set; }
            /// <summary>
            /// 用户的标识,对当前公众号唯一
            /// </summary>
            public string openid { get; set; }
            /// <summary>
            /// 用户的昵称
            /// </summary>
            public string nickname { get; set; }
            /// <summary>
            /// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
            /// </summary>
            public int sex { get; set; }
            /// <summary>
            ///用户的语言,简体中文为zh_CN
            /// </summary>
            public string language { get; set; }
            /// <summary>
            /// 用户所在城市
            /// </summary>
            public string city { get; set; }
            /// <summary>
            /// 用户所在省份
            /// </summary>
            public string province { get; set; }
            /// <summary>
            /// 用户所在国家
            /// </summary>
            public string country { get; set; }
            /// <summary>
            /// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
            /// </summary>
            public string headimgurl { get; set; }
            /// <summary>
            /// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
            /// </summary>
            public long subscribe_time { get; set; }
            /// <summary>
            /// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
            /// </summary>
            public string unionid { get; set; }
            /// <summary>
            /// 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
            /// </summary>
            public string remark { get; set; }
            /// <summary>
            /// 用户所在的分组ID(兼容旧的用户分组接口)
            /// </summary>
            public int groupid { get; set; }
            /// <summary>
            /// 用户标签
            /// </summary>
            public int[] tagid_list { get; set; }
            /// <summary>
            /// 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
            /// </summary>
            public string subscribe_scene { get; set; }
            /// <summary>
            /// 二维码扫码场景(开发者自定义)
            /// </summary>
            public int qr_scene { get; set; }
            /// <summary>
            /// 二维码扫码场景描述(开发者自定义)
            /// </summary>
            public string qr_scene_str { get; set; }
        }
    
        /// <summary>
        /// 批量获取用户基本信息返回结果
        /// </summary>
        public class BatchGetUserInfoJsonResult : WxJsonResult
        {
            public List<UserInfoJson> user_info_list { get; set; }
        }
    }
    View Code

    开放平台的用户:Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo.cs 增加了  [Serializable],比公众号少了不少属性字段

    /*----------------------------------------------------------------
        Copyright (C) 2018 Senparc
        
        文件名:OAuthUserInfo.cs
        文件功能描述:通过OAuth的获取到的用户信息
        
        
        创建标识:Senparc - 20150712
        
    ----------------------------------------------------------------*/
    
    using System;
    
    namespace Senparc.Weixin.Open.OAuthAPIs
    {
        /// <summary>
        /// 通过OAuth的获取到的用户信息(snsapi_userinfo=scope)
        /// </summary>
        [Serializable]
        public class OAuthUserInfo
        {
            public string openid { get; set; }
            public string nickname { get; set; }
            /// <summary>
            /// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
            /// </summary>
            public int sex { get; set; }
            public string province { get; set; }
            public string city { get; set; }
            public string country { get; set; }
            /// <summary>
            /// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
            /// </summary>
            public string headimgurl { get; set; }
            /// <summary>
            /// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
            /// 作者注:其实这个格式称不上JSON,只是个单纯数组。
            /// </summary>
            public string[] privilege { get; set; }
            /// <summary>
            /// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN
            /// </summary>
            public string unionid { get; set; }
        }
    }
    View Code

    我想在开放平台也能获取到公众号一样的用户信息,进行了如下改造 CustomWechatOpenOAuthAttribute

    //-----------------------------------------------------------------------
    // <copyright file="CustomOAuthAttribute.cs" company="FenSiShengHuo, Ltd.">
    //     Copyright (c) 2018 , All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    
    using System;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Mvc;
    
    namespace DotNet.WeChat.MVC.Filters
    {
        using DotNet.MVC.Infrastructure.Utilities;
        using DotNet.Utilities;
        using DotNet.WeChat.CommonService;
        using Senparc.Weixin.MP.MvcExtension;
    
        /// <summary>
        /// CustomOAuthAttribute
        ///  参考  Senparc.Weixin.MP.MvcExtension.SenparcOAuthAttribute 进行了重写
        /// 
        /// OAuth自动验证,可以加在Action或整个Controller上
        /// 
        /// 修改纪录
        /// 
        /// 2018-03-29 版本:1.0 JiShiYu 创建文件。     
        /// 
        /// <author>
        ///     <name>JiShiYu</name>
        ///     <date>2018-03-29</date>
        /// </author>
        /// </summary>
        public class CustomWechatOpenOAuthAttribute : SenparcOAuthAttribute
        {
            /// <summary>
            ///  OAuth自动验证,可以加在Action或整个Controller上
            /// </summary>
            /// <param name="appId"></param>
            /// <param name="oauthCallbackUrl"></param>
            public CustomWechatOpenOAuthAttribute(string appId = null, string oauthCallbackUrl = null)
                : base(appId, oauthCallbackUrl)
            {
                base._appId = base._appId ?? WebConfigurationManager.AppSettings["WeixinAppId"];
                base._oauthCallbackUrl = base._oauthCallbackUrl ?? "/Admin/WechatOpen/OAuthOpenCallback";
            }
    
            public override bool IsLogined(HttpContextBase httpContext)
            {
                if (httpContext.Request.Url.Host.IndexOf("fensishenghuo.com", StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    // return httpContext != null && httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] != null;
                    if (httpContext != null)
                    {
                        if (httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] != null)
                        {
                            WechatUserInfo wechatUserInfo = httpContext.Session[GlobalSetting.WechatOpenIdSessionKey] as WechatUserInfo;
                            if (wechatUserInfo != null && wechatUserInfo.OpenUserInfo != null)
                            {
                                return true;
                            }
                        }
                    }
                }
                return false;
                //也可以使用其他方法如Session验证用户登录
                //return httpContext != null && httpContext.User.Identity.IsAuthenticated;
            }
    
    
    #if NET35 || NET40 || NET45 || NET461|| NET462
            private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
            {
                validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
            }
    #endif
    
    
    #if NET35 || NET40 || NET45 || NET461|| NET462
            public override void OnAuthorization(AuthorizationContext filterContext)
    #else
            public override void OnAuthorization(AuthorizationFilterContext filterContext)
    #endif
            {
                if (filterContext == null)
                {
                    throw new ArgumentNullException("filterContext");
                }
    
                if (AuthorizeCore(filterContext.HttpContext))
                {
                    // ** IMPORTANT **
                    // Since we're performing authorization at the action level, the authorization code runs
                    // after the output caching module. In the worst case this could allow an authorized user
                    // to cause the page to be cached, then an unauthorized user would later be served the
                    // cached page. We work around this by telling proxies not to cache the sensitive page,
                    // then we hook our custom authorization code into the caching mechanism so that we have
                    // the final say on whether a page should be served from the cache.
    
    #if NET35 || NET40 || NET45 || NET461|| NET462
                    HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
                    cachePolicy.SetProxyMaxAge(new TimeSpan(0));
                    cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
    #endif
                }
                else
                {
                    if (IsLogined(filterContext.HttpContext))
                    {
    
                    }
                    else
                    {
                        var callbackUrl = Senparc.Weixin.HttpUtility.UrlUtility.GenerateOAuthCallbackUrl(filterContext.HttpContext, _oauthCallbackUrl);
                        var state = string.Format("{0}|{1}", "FromSenparc", DateTime.Now.Ticks);
                        //var url = Senparc.Weixin.MP.AdvancedAPIs.OAuthApi.GetAuthorizeUrl(_appId, callbackUrl, state, _oauthScope);
    
                        string componentAppId = WebConfigurationManager.AppSettings["Component_Appid"];
    
                        var url = Senparc.Weixin.Open.OAuthAPIs.OAuthApi.GetAuthorizeUrl(_appId, componentAppId, callbackUrl, state, new[] { Senparc.Weixin.Open.OAuthScope.snsapi_userinfo, Senparc.Weixin.Open.OAuthScope.snsapi_base });
                        NLogHelper.Info("url=" + url);
    
                        filterContext.Result = new RedirectResult(url);
                    }
                }
            }
    
    #if NET35 || NET40 || NET45 || NET461|| NET462
            // This method must be thread-safe since it is called by the caching module.
            protected override HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
            {
                if (httpContext == null)
                {
                    throw new ArgumentNullException("httpContext");
                }
    
                bool isAuthorized = AuthorizeCore(httpContext);
                return (isAuthorized) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
            }
    #endif
        }
    }

    其中WechatUserInfo是我扩展的一个类:

    //-----------------------------------------------------------------------
    // <copyright file="WechatUserInfo" company="FenSiShengHuo, Ltd.">
    //     Copyright (c) 2018 , All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    
    using DotNet.Utilities;
    using Senparc.Weixin.MP.AdvancedAPIs.User;
    using Senparc.Weixin.Open.OAuthAPIs;
    using System;
    
    namespace DotNet.WeChat.CommonService
    {
        /// <summary>
        /// WechatUserInfo
        /// 
        /// 微信用户
        /// 
        /// 修改纪录
        /// 
        /// 2018-07-11 版本:1.0 JiShiYu 创建文件。     
        /// 
        /// <author>
        ///     <name>JiShiYu</name>
        ///     <date>2018-07-11</date>
        /// </author>
        /// </summary>
        [Serializable]
        public class WechatUserInfo
        {
            /// <summary>
            /// 公众号的用户信息
            /// </summary>
            public UserInfoJson MPUserInfo { set; get; }
    
            /// <summary>
            /// 开放平台的用户信息
            /// </summary>
            public OAuthUserInfo OpenUserInfo { set; get; }
    
            /// <summary>
            /// 系统的用户信息
            /// </summary>
            public BaseUserInfo UserInfoBase { set; get; }
        }
    }
    /Admin/WechatOpen/OAuthOpenCallback 开放平台回调方法处理:
            /// <summary>
            ///  开放平台 网页授权回调  CustomWechatOpenOAuthAttribute 中使用
            ///  这个搞定,就可以不依赖主公众号的回调地址配置了
            /// </summary>
            /// <param name="code"></param>
            /// <param name="state"></param>
            /// <param name="appId"></param>
            /// <param name="returnUrl"></param>
            /// <returns></returns>
            public ActionResult OAuthOpenCallback(string code, string state, string appId, string returnUrl)
            {
                if (string.IsNullOrWhiteSpace(code))
                {
                    return Content("您拒绝了授权!");
                }
    
                if (!state.Contains("|"))
                {
                    //这里的state其实是会暴露给客户端的,验证能力很弱,这里只是演示一下
                    //实际上可以存任何想传递的数据,比如用户ID
                    return Content("验证失败!请从正规途径进入!1001");
                }
    
                Senparc.Weixin.Open.OAuthAPIs.OAuthAccessTokenResult result = null;
    
                //通过,用code换取access_token
                try
                {
                    var componentAccessToken = ComponentContainer.GetComponentAccessToken(componentAppId);
                    result = Senparc.Weixin.Open.OAuthAPIs.OAuthApi.GetAccessToken(appId, componentAppId, componentAccessToken, code);
                }
                catch (Exception ex)
                {
                    return Content(ex.Message);
                }
    
                if (result.errcode != Senparc.Weixin.ReturnCode.请求成功)
                {
                    return Content("错误:" + result.errmsg);
                }
                //下面2个数据也可以自己封装成一个类,储存在数据库中(建议结合缓存)
                //如果可以确保安全,可以将access_token存入用户的cookie中,每一个人的access_token是不一样的
                Session["OAuthAccessTokenStartTime"] = DateTime.Now;
                Session["OAuthAccessToken"] = result;
    
                //因为第一步选择的是OAuthScope.snsapi_userinfo,这里可以进一步获取用户详细信息
                try
                {
                    // 开放平台的用户信息
                    Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo openUserInfo = Senparc.Weixin.Open.OAuthAPIs.OAuthApi.GetUserInfo(result.access_token, result.openid);
                    // 公众号的用户信息
                    //UserInfoJson mpUserInfo = UserApi.Info(result.access_token, result.openid);
                    UserInfoJson mpUserInfo = UserApi.Info(appId, result.openid);
    
                    // 实现将该用户存储起来
                    // return View(userInfo);
    
                    // 改为存储UserInfoJson对象
                    WechatUserInfo wechatUserInfo = new WechatUserInfo();
                    wechatUserInfo.OpenUserInfo = openUserInfo;
                    wechatUserInfo.MPUserInfo = mpUserInfo;
    
                    NLogHelper.Info("OAuthOpenCallback,WechatUserInfo=" + wechatUserInfo.FastToJson() + ",returnUrl=" + returnUrl);
                    // 改为存储UserInfoJson对象
                    Session[GlobalSetting.WechatOpenIdSessionKey] = wechatUserInfo;
                }
                catch (ErrorJsonResultException ex)
                {
                    return Content(ex.Message);
                }
    
                return Redirect(returnUrl);
            }

    大家对这个在开放平台获取用户授权方式有什么建议呢?

  • 相关阅读:
    centos7物理机a start job is running for dev-mapper-centosx2dhome.device
    jenkins pipeline流水线
    nginx 加载慢 负载均衡不均衡
    山田预发环境发布脚本
    prometheus 监控容器
    maven私服安装使用
    日志清理
    ERROR 1046 (3D000) at line 1: No database selected
    网络工程学习经典书籍推荐
    每日一句
  • 原文地址:https://www.cnblogs.com/hnsongbiao/p/9293413.html
Copyright © 2020-2023  润新知