• 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>
                    测试带returnUrl@(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=" 50%"/>(直接调用可能看不到,需要抓取)
        </p>
    </body>
    </html>
    UserInfoCallback

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

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

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

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

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

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

    成功后获取用户信息

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

    总结

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

  • 相关阅读:
    市场规模的估算
    C#中的线程(一)入门 转载
    2.设计模式-Abstract Factory 抽象工厂模式
    1.设计模式
    Microsoft.Jet.OLEDB.4.0读取EXCEL数据
    转载--加盐密码哈希:如何正确使用
    ragel学习资源整合
    开源库xlslib跨平台编译
    WPF开源框架以及经典博客
    (转载)值得推荐的C/C++框架和库 (真的很强大)
  • 原文地址:https://www.cnblogs.com/ymnets/p/6051866.html
Copyright © 2020-2023  润新知