ASP.NET MVC5+EF6+EasyUI 后台管理系统(76)-微信公众平台开发-网页授权

前言

网页授权是:应用或者网站请求你用你的微信帐号登录,同意之后第三方应用可以获取你的个人信息

网上说了一大堆参数,实际很难理解和猜透,我们以实际的代码来演示比较通俗易懂

配置

实现之前我们必须配置用户授权获取用户信息的域名或者IP。正式公众号只能配置(域名)

第一步:登录公众号平台

跟我们之前配置公众号平台信息一样

第二步: 打开开发者工具

拉到下半部分位置的网页账号

第三步:配置你的授权回调域名

实现

我们模拟一个需要授权的页面(代码提供来自Senparc)

第一步:新建一个Controller

里面只有2个方法,一个是Index即需要授权的页面,第二个是BaseCallback页面即授权成功后要跳转的页面

  public class OAuth2Controller : Controller
    {
        [Dependency]
        public IWC_OfficalAccountsBLL account_BLL { get; set; }
        /// <summary>
        ///
        /// </summary>
        /// <param name="returnUrl">用户尝试进入的需要登录的页面</param>
        /// <returns></returns>
        public ActionResult Index(string returnUrl)
        {
            WC_OfficalAccountsModel model = account_BLL.GetCurrentAccount();

            //获取用户保存的cookie
            //判断是否已经授权过

            var state = "YMNETS-" + DateTime.Now.Millisecond;//随机数,用于识别请求可靠性
            Session["State"] = state;//储存随机数到Session

            ViewData["returnUrl"] = returnUrl;

            //此页面引导用户点击授权
            ViewData["UrlUserInfo"] =
                OAuthApi.GetAuthorizeUrl(model.AppId,
                "http://ymnets.imwork.net/WC/OAuth2/UserInfoCallback?returnUrl=" + returnUrl.UrlEncode(),
                state, OAuthScope.snsapi_userinfo);
            ViewData["UrlBase"] =
                OAuthApi.GetAuthorizeUrl(model.AppSecret,
                "http://ymnets.imwork.net/WC/OAuth2/BaseCallback?returnUrl=" + returnUrl.UrlEncode(),
                state, OAuthScope.snsapi_base);
            return View();
        }

        /// <summary>
        /// OAuthScope.snsapi_userinfo方式回调
        /// </summary>
        /// <param name="code"></param>
        /// <param name="state"></param>
        /// <param name="returnUrl">用户最初尝试进入的页面</param>
        /// <returns></returns>
        public ActionResult UserInfoCallback(string code, string state, string returnUrl)
        {
            if (string.IsNullOrEmpty(code))
            {
                return Content("您拒绝了授权!");
            }

            if (state != Session["State"] as string)
            {
                //这里的state其实是会暴露给客户端的,验证能力很弱,这里只是演示一下,
                //建议用完之后就清空,将其一次性使用
                //实际上可以存任何想传递的数据,比如用户ID,并且需要结合例如下面的Session["OAuthAccessToken"]进行验证
                return Content("验证失败!请从正规途径进入!");
            }

            OAuthAccessTokenResult result = null;

            //通过,用code换取access_token
            try
            {
                WC_OfficalAccountsModel model = account_BLL.GetCurrentAccount();
                result = OAuthApi.GetAccessToken(model.AppId, model.AppSecret, code);
            }
            catch (Exception ex)
            {
                return Content(ex.Message);
            }
            if (result.errcode != ReturnCode.请求成功)
            {
                return Content("错误:" + result.errmsg);
            }
            //下面2个数据也可以自己封装成一个类,储存在数据库中(建议结合缓存)
            //如果可以确保安全,可以将access_token存入用户的cookie中,每一个人的access_token是不一样的
            Session["OAuthAccessTokenStartTime"] = DateTime.Now;
            Session["OAuthAccessToken"] = result;

            //因为第一步选择的是OAuthScope.snsapi_userinfo,这里可以进一步获取用户详细信息
            try
            {
                if (!string.IsNullOrEmpty(returnUrl))
                {
                    return Redirect(returnUrl);
                }

                OAuthUserInfo userInfo = OAuthApi.GetUserInfo(result.access_token, result.openid);
                return View(userInfo);
            }
            catch (ErrorJsonResultException ex)
            {
                return Content(ex.Message);
            }
        }
    }
}

获取接口的方法

 /*此接口不提供异步方法*/
        /// <summary>
        /// 获取验证地址
        /// </summary>
        /// <param name="appId">公众号的唯一标识</param>
        /// <param name="redirectUrl">授权后重定向的回调链接地址,请使用urlencode对链接进行处理</param>
        /// <param name="state">重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节</param>
        /// <param name="scope">应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)</param>
        /// <param name="responseType">返回类型,请填写code(或保留默认)</param>
        /// <param name="addConnectRedirect">加上后可以解决40029-invalid code的问题(测试中)</param>
        /// <returns></returns>
        public static string GetAuthorizeUrl(string appId, string redirectUrl, string state, OAuthScope scope, string responseType = "code", bool addConnectRedirect = true)
        {
            var url =
                string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}{5}#wechat_redirect",
                                appId.AsUrlData(), redirectUrl.AsUrlData(), responseType.AsUrlData(), scope.ToString("g").AsUrlData(), state.AsUrlData(),
                                addConnectRedirect ? "&connect_redirect=1" : "");

            /* 这一步发送之后,客户会得到授权页面,无论同意或拒绝,都会返回redirectUrl页面。
             * 如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。这里的code用于换取access_token(和通用接口的access_token不通用)
             * 若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE
             */
            return url;
        }

通过这个接口就可以组成调用微信API的参数

第二步:界面数据

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>OAuth2.0授权测试</title>
    <style>
        .green {
            color: green;
        }
    </style>
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery")
</head>
<body>

    <h2>OAuth2.0授权测试</h2>
    <p>注意:此页面仅供测试,测试号随时可能过期。请将此DEMO部署到您自己的服务器上,并使用自己的appid和secret。</p>
    <p>
        当前returnUrl:
        @if (ViewData["returnUrl"] == null || ViewData["returnUrl"] as string == "")
        {
            <span>
                <strong>不带returnUrl</strong>。
            </span><br />
            <span class="green">使用不带returnUrl的页面会停留在Callback页面,此页面如果刷新(或后退到此页面),会导致code过期的错误,只建议在测试阶段使用。</span>
            <br/>
            <span>
                测试带[email protected](Html.ActionLink("点击这里", "Index", new { returnUrl = Url.Action("TestReturnUrl") }))。
            </span>
        }
        else
        {
            <span><strong>@ViewData["returnUrl"]</strong>。</span><br />
            <span class="green">携带returnUrl后,页面最终会跳转到returnUrl对应页面,避免刷新页面导致code的错误。</span>
        }
    </p>
    <p><a href="@ViewData["UrlUserInfo"]">点击这里测试snsapi_userinfo</a></p>
    <p>
        将要链接到的地址:<br />
        <textarea rows="10" cols="40">@ViewData["UrlUserInfo"]</textarea>
    </p>
    <p><a href="@ViewData["UrlBase"]">点击这里测试snsapi_base</a></p>
    <p>
        将要链接到的地址:<br />
        <textarea rows="10" cols="40">@ViewData["UrlBase"]</textarea>
    </p>
</body>
</html>

Index

@model Senparc.Weixin.MP.AdvancedAPIs.OAuth.OAuthUserInfo

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>OAuth2.0授权测试授权成功</title>
</head>
<body>
    <h2>OAuth2.0授权测试授权成功!</h2>
    @if (ViewData.ContainsKey("ByBase"))
    {
        <p><strong>您看到的这个页面来自于snsapi_base授权,因为您已关注本微信,所以才能查询到详细用户信息,否则只能进行常规的授权。</strong></p>
    }
    else
    {
        <p><strong>您看到的这个页面来自于snsapi_userinfo授权,可以直接获取到用户详细信息。</strong></p>
    }
    <p>下面是通过授权得到的您的部分个人信息:</p>
    <p>openid:@Model.openid</p>
    <p>nickname:@Model.nickname</p>
    <p>country:@Model.country</p>
    <p>province:@Model.province</p>
    <p>city:@Model.city</p>
    <p>sex:@Model.sex</p>
    @if (Model.unionid != null)
    {
        <p>unionid:@Model.unionid</p>
    }
    <p>
        头像:<br />
        <img src="@Model.headimgurl" style="width: 50%"/>(直接调用可能看不到,需要抓取)
    </p>
</body>
</html>

UserInfoCallback

第三步:测试(必须在微信里面测试)

在公众号里面调用这个链接,我们在图文回复中,设置一个链接是指向这个授权页面的测试一下,即:

http://ymnets.imwork.net/WC/OAuth2/Index?returnUrl=http://ymnets.imwork.net/WC/OAuth2/UserInfoCallBack

理论是只要能通过微信打开这个链接就好,什么方式都是可以的

注意格式:retuenUrl是校验成功要返回的Url地址

----------------------------------演示开始--------------------------------------

----------------------------------演示结束--------------------------------------

总结

授权之后我们应该利用cookie来记录用户登录状况,下次登录时候判断是否有cookie来跳过授权

参考代码下载:https://github.com/JeffreySu/WeiXinMPSDK

时间: 2024-12-04 12:46:14

ASP.NET MVC5+EF6+EasyUI 后台管理系统(76)-微信公众平台开发-网页授权的相关文章

ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 日程管理   http://www.cnblogs.com/ymnets/p/7094914.html 任务调度系统界面 http://www.cnblogs.com/ymnets/p/5065154.html 系统权限全套完整图  http://www.cnblogs.com/ymnets/p/5065201.html 系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统-关于WebApi的用法

1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+EasyUI 后台管理系统(2)-WebApi与Unity注入-配置文件 3:ASP.NET MVC5+EF6+EasyUI 后台管理系统(3)-MVC WebApi 用户验证 (1) 4:ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-MVC WebApi 用户验证 (2) 以往我们讲

ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理

最近代码出现分享问题,360云盘宣布混不下去,所有分享的连接都失效了,最近有时间会把代码转移到百度云,再把文章的代码补回去 前言 本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号也提供了相应的接口另我们本地可以操作.我们主要是同步到本地,这样我们可以自己为用户定义更多的信息,以及与本地的业务更好的对接起来. 实现 一.关注与订阅事件 看到我们之前的消息处理类 我们需要扩展一个事件

ASP.NET MVC5+EF6+EasyUI 后台管理系统(84)-Quartz 作业调度用法详解一

前言 我从Quartz2.0开始使用,并对其进行了封装了界面,可以参考 http://www.cnblogs.com/ymnets/p/5065154.html 最近拿出来进行了优化,并升级到最新版,温故而知新嘛 当初教程较少,并且是英文,现在很多地方都有中文的教程也是学习起来事半功倍 Quartz能实现什么? 他类似于SQL Server的代理与Timer定时器: 1.指定时间执行一条SQL语句或存储过程 2.指定时间发送邮件(执行一个C#方法) 3.有规律的定时执行想要做的事情(通过配置Cr

ASP.NET MVC5+EF6+EasyUI 后台管理系统(73)-微信公众平台开发-消息管理

前言 回顾上一节,我们熟悉的了解了消息的请求和响应,这一节我们来建立数据库的表,表的设计蛮复杂 你也可以按自己所分析的情形结构来建表 必须非常熟悉表的结果才能运用这张表,这表表的情形涵盖比较多 思维导图 我这个人比较喜欢用思维导图来分析和表达一些模型: 表结构 根据思维导图,我们可以建立的表可以是3张表:消息表,规则表,类型表 消息表:实际的消息 规则表:文本.图文.语音等 类型表:文本.图文.语音(默认回复,订阅回复) 也可以是两张表:规制表,消息表(+一个类型字段) 我这里只设计一张表:消息

ASP.NET MVC5+EF6+EasyUI 后台管理系统(999)-如何使用

前言 这篇文本讲述了这个框架的使用方式,及一些疑问的答疑,更加精准的使用这个框架来建立功能 经过几个版本的迭代,系统使用更加方便,代码更加简洁也更加的智能,所以之前61节的文章也需要重新编排 对项目的了解 项目没有特别难以理解的类库, 就当成一个普通的MVC,三层项目看待即可 目录 我们只需要分为几步就能快速的建立一个具有权限的功能 表设计及约定 生成代码(代码生成器及TT模板) 配置(URL的配置及权限设置) 1.表设计及约定 框架表的设计必须遵循约定来设计,否则生成的代码需要再重载,而约定只

ASP.NET MVC5+EF6+EasyUI 后台管理系统(92)-打印EasyUI 的datagrid表格

前言 应用系统有时候需要打印Datagrid的表格内容,我们本节就来学习打印datagrid内容 打印主要使用:web打印(我们之前有讲过web打印插件jqprint) + 将datagrid重新编制成可以打印的html格式 一.建立一个普通的例子 我们使用官方下载的demo下的datagrid basic.html代码就好 引入Jqgrid打印插件,并增加一个按钮来触发打印事件 <!DOCTYPE html> <html> <head> <meta charse

ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1)

系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问 本文通过Basic 方式进行基础认证Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能,本文主要作为本人备忘使用,如能给予人帮助,深感荣幸,欢迎讨论和指正,下面梳

ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-创建项目解决方案

系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 设计中术语,概念这种东西过于模糊,我们必须学习累积才能认识这些概念模型. 我无法用文章来下详细解析此系统的深层概念,需要大家在日常工作中实践和意会, 推荐一本.net的设计书籍<Microsoft .NET企业级应用架构设计>这本书详细的讲述了接口编程,面向方面编程 构建解决方案 现在我们开始构建我们的解决方案吧,分别建立类库 Apps.BLL (业务层) Apps.IBLL (业务层接口) Apps.DAL (数据