Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明

官方地址:  http://weixin.senparc.com php

原文地址:http://www.cnblogs.com/szw/p/3764275.html html

 

 紧接上一篇《Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明》,这里专讲OAuth2.0。git

理解OAuth2.0

  首先咱们经过一张图片来了解一下OAuth2.0的运做模式:github

  从上图咱们能够看到,整个过程进行了2次“握手”,最终利用受权的AccessToken进行一系列的请求,相关的过程说明以下:api

  • A:由客户端向服务器发出验证请求,请求中通常会携带这些参数
    • ID标识,例如appId
    • 验证后跳转到的URL(redirectUrl)
    • 状态参数(可选)
    • 受权做用域scope(可选)
    • 响应类型(可选)
  • B:服务器返回一个grant受权标识(微信默认状况下称之为code),相似于一个一次性的临时字符串密钥。若是在A中提供了redirectUrl,这里服务器会作一次跳转,带上grant和状态参数,访问redirectUrl。
  • C:客户端的redirectUrl对应页面,凭借grant再次发起请求,此次请求一般会携带一些敏感信息:
    • ID标识
    • 密码
    • grant字符串(code)
    • grant类型(可选,微信中默认为code)
  • D:服务器验证ID标识、密码、grant都正确以后,返回AccessToken(注意,这里的AccessToken和以前通用接口、高级接口介绍的AccessToken没有关系,不能交叉使用)
  • E:客户端凭借AccessToken请求一系列的API,在此过程当中再也不会携带appId,Secret,grant等敏感的信息。
  • F:服务器返回请求结果。

微信的OAuth2.0使用

  了解了OAuth2.0的基本原理以后,咱们来看一下OAuth2.0在微信中是如何运用的。浏览器

  假设一个场景:用户进入了一个微信公众帐号,随后经过消息中的连接,在微信内嵌浏览器中打开了一个游戏网页,这个游戏须要用户登陆而且记录用户的游戏得分。安全

  这种状况下咱们有两种处理方式:服务器

  1. 让用户在网页中进行注册、登陆(而且每次打开这个网页均可能要从新进行登陆,由于微信内置浏览器的cookie保存时间很是短),这个固然是个很坑爹的设计。
  2. 利用OAuth2.0。在用户进入这个页面的时候,先判断用户是否登陆,若是没有,自动跳转到OAuth2.0受权页面,这个页面又自动进行了上述ABCD一系列验证,再经过EF获得用户的OpenId甚至更加详细的信息(包括头像),自动完成登陆(或必要的注册)过程,随后用户以登陆状态直接进入游戏。

  能够看出,使用OAuth2.0大幅度提升了用户体验,而且能够自动绑定识别用户微信OpenId。微信

  须要注意的是,上面提到的“OAuth2.0受权页面”还有两种形式:cookie

  1. 当请求A中的Scope为snsapi_base时,整个受权过程自动完成,用户的客户端不会有任何中间页面显示,可是受权的结果仅能获取用户的OpenId(无论用户是否已关注,固然若是用户是关注用户,再次利用高级接口中的用户信息接口,利用OpenId获取用户资料也是能够的,只不过绕了几个弯)
  2. 当请求A中的Scope为snsapi_userinfo时,须要提供一个受权页面(相似不少网站利用微博帐号、QQ号登录的那种受权),仅当用户赞成以后,当即获取到用户的详细信息,这里的用户必须是已经关注的用户。

  也就是说,snsapi_base的方法能够“神不知鬼不觉”地获取用户OpenId,全自动完成登陆注册过程,可是信息量有限;snsapi_userinfo须要用户在指定界面上受权以后,自动完成整个过程,这个受权有一个时间段,超过期间后须要从新询问用户。

Senparc.Weixin.MP OAuth2.0接口

  源文件文件夹:Senparc.Weixin.MP/AdvancedAPIs/OAuth

  相比其余接口OAuth2.0略微复杂,相关内容将在下一篇专门进行介绍:Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明

  源代码中相关方法以下:

复制代码
namespace Senparc.Weixin.MP.AdvancedAPIs
{
    //官方文档:http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code

    /// <summary>
    /// 应用受权做用域
    /// </summary>
    public enum OAuthScope
    {
        /// <summary>
        /// 不弹出受权页面,直接跳转,只能获取用户openid
        /// </summary>
        snsapi_base,
        /// <summary>
        /// 弹出受权页面,可经过openid拿到昵称、性别、所在地。而且,即便在未关注的状况下,只要用户受权,也能获取其信息
        /// </summary>
        snsapi_userinfo
    }

    public static class OAuth
    {
        /// <summary>
        /// 获取验证地址
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="redirectUrl"></param>
        /// <param name="state"></param>
        /// <param name="scope"></param>
        /// <param name="responseType"></param>
        /// <returns></returns>
        public static string GetAuthorizeUrl(string appId, string redirectUrl, string state, OAuthScope scope, string responseType = "code")
        {
            var url =
                string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect",
                                appId, redirectUrl.UrlEncode(), responseType, scope, state);

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

        /// <summary>
        /// 获取AccessToken
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <param name="code">code做为换取access_token的票据,每次用户受权带上的code将不同,code只能使用一次,5分钟未被使用自动过时。</param>
        /// <param name="grantType"></param>
        /// <returns></returns>
        public static OAuthAccessTokenResult GetAccessToken(string appId, string secret, string code, string grantType = "authorization_code")
        {
            var url =
                string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type={3}",
                                appId, secret, code, grantType);

            return CommonJsonSend.Send<OAuthAccessTokenResult>(null, url, null, CommonJsonSendType.GET);
        }

        /// <summary>
        /// 刷新access_token(若是须要)
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="refreshToken">填写经过access_token获取到的refresh_token参数</param>
        /// <param name="grantType"></param>
        /// <returns></returns>
        public static OAuthAccessTokenResult RefreshToken(string appId, string refreshToken, string grantType = "refresh_token")
        {
            var url =
                string.Format("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={0}&grant_type={1}&refresh_token={2}",
                                appId, grantType, refreshToken);

            return CommonJsonSend.Send<OAuthAccessTokenResult>(null, url, null, CommonJsonSendType.GET);
        }

        public static OAuthUserInfo GetUserInfo(string accessToken,string openId)
        {
            var url = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}",accessToken,openId);
            return CommonJsonSend.Send<OAuthUserInfo>(null, url, null, CommonJsonSendType.GET);
        }
    }
}
复制代码

  具体的示例方法见Senparc.Weixin.MP.Sample/Controllers/OAuth2Controller.cs,以及对应视图的代码。

注意点

  1. 必须是经过认证的服务号才可使用OAuth接口。
  2. 接口中用到的AccessToken和高级接口(包括通用接口)中用到的AccessToken互不相关,即便他们都是经过相同的AppId和Secret获得的。
  3. 目前官方的受权页面不是100%稳定,有时候须要多点几回才能顺利经过,若是发现此类状况,须要作一些判断反复请求,至少在表面上能够不让用户看到错误页面。
  4. 出于安全,在使用OAuth2.0以前,须要进入到微信后台的【个人服务】对回调页面的域名进行设置:

 

 

  系列教程索引:http://www.cnblogs.com/szw/archive/2013/05/14/weixin-course-index.html

 

 

新浪微博:@苏震巍 QQ:498977166

http://szw.cnblogs.com/研究、探讨ASP.NET转载请注明出处和做者,谢谢!

相关文章
相关标签/搜索