第一篇:理论

如果一个用户并未关注某个公众号,只是在微信内打开了公众号web服务器上的某个网页,要如何获取用户的openid以及用户的微信信息,以便实现业务逻辑呢?本篇讲述网页授权OAuth获取微信用户的关键信息。先来了解一个概念:

网页授权

如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。

微信网页授权能力调整公告

为进一步规范能力使用,保障用户合法权益,平台将对微信网页授权能力进行调整。 当开发者在网页中在不规范使用发起 snsapi_userinfo 网页授权时,微信将默认打开网页快照页模式进行基础浏览。 能力调整将于 2022 年 7 月 12 日 24 时生效。详情点击查看原公告《微信网页授权能力调整公告》。

关于网页授权回调域名的说明

  1. 在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
  2. 授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com 无法进行OAuth2.0鉴权

关于网页授权的两种 scope 的区别说明

  1. 以snsapi_base为 scope 发起的网页授权,是用来获取进入页面的用户的 openid 的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
  2. 以snsapi_userinfo为 scope 发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
  3. 用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户 OpenID 来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

关于网页授权access_token和普通access_token的区别

  1. 微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
  2. 其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。

关于特殊场景下的静默授权

  1. 上面已经提到,对于以snsapi_base为 scope 的网页授权,就静默授权的,用户无感知;
  2. 对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是 scope 为snsapi_userinfo,也是静默授权,用户无感知。

开发指南

网页授权流程分为四步:

  1. 引导用户进入授权页面同意授权,获取code
  2. 通过 code 换取网页授权access_token(与基础支持中的access_token不同)
  3. 如果需要,开发者可以刷新网页授权access_token,避免过期
  4. 通过网页授权access_token和 openid 获取用户基本信息(支持 UnionID 机制)

第一步:用户同意授权,获取code

在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(已认证服务号,默认拥有 scope 参数中的snsapi_base和snsapi_userinfo 权限),引导关注者打开如下页面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有 scope 参数对应的授权作用域权限。

尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问

参考链接(请在微信客户端中打开此链接体验):

scope为snsapi_base:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

scope为snsapi_userinfo:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

第二步:通过 code 换取网页授权access_token

首先请注意,这里通过 code 换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。

尤其注意:由于公众号的 secret 和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

请求方法

获取 code 后,请求以下链接获取access_token:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

第三步:刷新access_token(如果需要)

由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。

请求方法

获取第二步的refresh_token后,请求以下链接获取access_token:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

第四步:拉取用户信息(需 scope 为 snsapi_userinfo)

如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和 openid 拉取用户信息了。

请求方法

http:GET(请使用 https 协议):

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

当一切正常时,返回的用户信息字段如下:

第二篇:实战

一、先准备一个专用类,直接上源码:

/*
*类名:QinMingWeixinOAuth
*归属:QinMing.WeixinOAuth命名空间
*用途:通过网页OAuth方式获取用户openid和access_token,进而可以获取微信用户的头像、昵称等信息
*作者:
*日期:8
*/using System;
using System.Web;
using System.Net;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using QinMing.Config;namespace QinMing.WeixinOAuth
{public  class QinMingWeixinOAuth : System.Web.UI.Page{/// <summary>/// 获取CODE,后期用于获取微信用户openid,静默,不需要用户确认/// </summary>public string GetCodeBase(string appid, string redirect_url){var state = "QinMing" + DateTime.Now.Millisecond;string RedirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=" + appid + "&redirect_uri=" + redirect_url+ "&response_type=code&scope=snsapi_base"+ "&state=" + state + "#wechat_redirect";return RedirectUrl;}/// <summary>/// 用CODE换取openid,适用于获取用户openid,在scope=snsapi_base使用/// </summary>public string GetOpenId(string code){string appid = QinMingConfig.Weixin_AppId;string secret = QinMingConfig.Weixin_AppSecret;string strResult="";string openid="";string strurl="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appid + "&secret="+ secret + "&code="+ code + "&grant_type=authorization_code";try{HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();Stream myStream = HttpWResp.GetResponseStream();StreamReader sr = new StreamReader(myStream, Encoding.UTF8);StringBuilder strBuilder = new StringBuilder();while (-1 != sr.Peek()){strBuilder.Append(sr.ReadLine());}strResult = strBuilder.ToString();JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));openid = obj["openid"].ToString().Replace("\"", "");return openid;}catch{strResult = "err";return strResult;}}/// <summary>/// 获取CODE,后期用于获取微信用户信息,需要用户确认;与上面GetCodeBase的差异只是scope=snsapi_userinfo部分/// </summary>public string GetCodeUserInfo(string appid, string redirect_url){var state = "QinMing" + DateTime.Now.Millisecond;string RedirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=" + appid + "&redirect_uri=" + redirect_url+ "&response_type=code&scope=snsapi_userinfo"+ "&state=" + state + "#wechat_redirect";return RedirectUrl;}/// <summary>/// 用CODE换取openid和AccessToken,适用于获取用户信息,在scope=snsapi_userinfo使用,切忌只能用在服务器端使用,不能传递到客户端,高风险/// </summary>public string GetOpenIdAndAccessToken(string code){string appid = QinMingConfig.Weixin_AppId;string secret = QinMingConfig.Weixin_AppSecret;string strResult="";string openid="";string access_token="";string strurl="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appid + "&secret="+ secret + "&code="+ code + "&grant_type=authorization_code";try{HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();Stream myStream = HttpWResp.GetResponseStream();StreamReader sr = new StreamReader(myStream, Encoding.UTF8);StringBuilder strBuilder = new StringBuilder();while (-1 != sr.Peek()){strBuilder.Append(sr.ReadLine());}strResult = strBuilder.ToString();JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));openid = obj["openid"].ToString().Replace("\"", "");access_token = obj["access_token"].ToString().Replace("\"", "");return openid + "|" + access_token;}catch{strResult = "err";return strResult;}}/// <summary>/// 获取用户信息,包含头像和昵称等/// </summary>public JObject GetUserInfo(string open_id, string access_token){string strResult = "";string strurl="https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + open_id + "&lang=zh_CN";try{HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strurl);HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();Stream myStream = HttpWResp.GetResponseStream();StreamReader sr = new StreamReader(myStream, Encoding.UTF8);StringBuilder strBuilder = new StringBuilder();while (-1 != sr.Peek()){strBuilder.Append(sr.ReadLine());}strResult = strBuilder.ToString();//更新weixin_user_info表中微信用户信息JObject tmpobj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));QinMingToolsDB.UpdateTable("update weixin_user_info set nickname='" + tmpobj["nickname"].ToString().Replace("\"", "") + "',"+ "headimgurl='" + tmpobj["headimgurl"].ToString().Replace("\"", "") + "',"+ "province='" + tmpobj["province"].ToString().Replace("\"", "") + "',"+ "city='" + tmpobj["city"].ToString().Replace("\"", "") + "',"+ "country='" + tmpobj["country"].ToString().Replace("\"", "") + "',"+ "sex='" + tmpobj["sex"].ToString().Replace("\"", "") + "' "+ " where openid='" + open_id + "'");}catch{strResult = "err";}JObject obj = (JObject)JsonConvert.DeserializeObject(HttpUtility.UrlDecode(strResult));return obj;}/*//正确返回时JObject格式如下{   "openid": "OPENID","nickname": NICKNAME,"sex": 1,"province":"PROVINCE","city":"CITY","country":"COUNTRY","headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46","privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"}*/}}

二、仅获取微信用户openid

使用方法:http://www.xxxx.com/weixin/RedirectWithOpenIdFirst.aspx?final_url=myweb.aspx

这样在myweb.aspx打开时将带入微信用户的openid参数。

RedirectWithOpenIdFirst.aspx源码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RedirectWithOpenIdFirst.aspx.cs" Inherits="Jjlm.RedirectWithOpenIdFirst" %>

RedirectWithOpenIdFirst.aspx.cs源码:

using System;
using System.Web;
using QinMing.Config;
using QinMing.WeixinOAuth;namespace Jjlm
{public partial class RedirectWithOpenIdFirst : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){string final_url = Request.QueryString["final_url"]; string appid = QinMingConfig.Weixin_AppId;string redirect_url = QinMingConfig.Url_WebServer + "/weixin/RedirectWithOpenIdSecond.aspx" + "?final_url=" + final_url;QinMingWeixinOAuth oauth = new QinMingWeixinOAuth();string newurl = oauth.GetCodeBase(appid, redirect_url);Response.Redirect(newurl);}}
}   

RedirectWithOpenIdSecond.aspx源码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RedirectWithOpenIdSecond.aspx.cs" Inherits="Jjlm.RedirectWithOpenIdSecond" %>

RedirectWithOpenIdSecond.aspx.cs源码:

using System;
using System.Web;
using QinMing.WeixinOAuth;namespace Jjlm
{public partial class RedirectWithOpenIdSecond : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){string final_url = Request.QueryString["final_url"]; string code = Request.QueryString["code"]; QinMingWeixinOAuth oauth=new QinMingWeixinOAuth();//仅获取openidstring open_id  = oauth.GetOpenId(code);Response.Redirect(final_url + "?open_id=" + open_id);}}
}   

三、获取微信用户openid和昵称、头像等信息

使用方法:http://www.xxxx.com/Coalition/OAuthOpenidAndUserinfoFirst.aspx?final_url=myweb.aspx

这样在myweb.aspx打开时将带入微信用户的openid参数,同时带入了昵称nickname以及头像head_img_url参数。

OAuthOpenidAndUserinfoFirst.aspx源码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="OAuthOpenidAndUserinfoFirst.aspx.cs" Inherits="Coalition.OAuthOpenidAndUserinfoFirst" %>

OAuthOpenidAndUserinfoFirst.aspx.cs源码:

using System;
using System.Web;
using QinMing.Config;
using QinMing.WeixinOAuth;namespace Coalition
{public partial class OAuthOpenidAndUserinfoFirst : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){string final_url = Request.QueryString["final_url"]; string appid = QinMingConfig.Weixin_AppId;string redirect_url = QinMingConfig.Url_WebServer + "/Coalition/OAuthOpenidAndUserinfoSecond.aspx" + "?final_url=" + final_url;QinMingWeixinOAuth oauth = new QinMingWeixinOAuth();string newurl = oauth.GetCodeUserInfo(appid, redirect_url);Response.Redirect(newurl);}}
}   

OAuthOpenidAndUserinfoSecond.aspx源码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="OAuthOpenidAndUserinfoSecond.aspx.cs" Inherits="Coalition.OAuthOpenidAndUserinfoSecond" %>

OAuthOpenidAndUserinfoSecond.aspx.cs源码:

using System;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using QinMing.WeixinOAuth;
using QinMing.Tools;namespace Coalition
{public partial class OAuthOpenidAndUserinfoSecond : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){string final_url = Request.QueryString["final_url"]; string code = Request.QueryString["code"]; QinMingWeixinOAuth oauth=new QinMingWeixinOAuth();//获取openid和access_tokenstring openid_accesstoken  = oauth.GetOpenIdAndAccessToken(code);//QinMingTools.WriteLog("oauth2.0获取信息测试", openid_accesstoken);//获取用户头像链接和昵称string[] array = openid_accesstoken.Split(new Char[] { '|' });string open_id = array[0];string access_token = array[1];JObject obj = oauth.GetUserInfo(open_id, access_token);string head_img_url = obj["headimgurl"].ToString().Replace("\"", "");string nickname = obj["nickname"].ToString().Replace("\"", "");Response.Redirect(final_url + "?open_id=" + open_id + "&head_img_url=" + head_img_url + "&nickname=" + nickname);}}
}   

重要提醒:通过网页获取微信用户的openid,除了用来实现线上销售等业务逻辑,常见的应用还有投票拉票、合伙人、裂变传播等。

实例:用C#.NET手把手教你做微信公众号开发(22)--网页里通过OAuth获取用户openid相关推荐

  1. 实例:用C#.NET手把手教你做微信公众号开发(20)--使用微信支付线上收款:jsapi方式

    在做线上.线下销售时,可以使用微信便捷支付,通过微信公众号收款有很多种收款方式,如下图: 今天我们来讲一下jsapi支付,场景就是在微信内打开某个页面,完成在线支付,同样一个网页,使用微信打开就是js ...

  2. 实例:用C#.NET手把手教你做微信公众号开发(21)--使用微信支付线上收款:H5方式

    在做线上.线下销售时,可以使用微信便捷支付,通过微信公众号收款有很多种收款方式,如下图: 今天我们来讲一下H5场景支付,使用手机浏览器打开就是H5方式,最常见的推广是短信内置链接,这种场景需要调用微信 ...

  3. 实例:用C#.NET手把手教你做微信公众号开发(3)--普通消息处理之图片

    本着简短.便于理解应用的原则,本系列文章每次只讲一个公众号知识点,给出一个应用实例,通过一个知识点帮助你掌握公众号一类应用的开发方法. 上一篇我们掌握了微信客户端.微信服务器.你的服务器之间的信息互动 ...

  4. 实例:用C#.NET手把手教你做微信公众号开发(19)--使用微信支付转账到微信粉丝零钱账户

    公众号给微信用户支付费用的方式有很多种,最常用的是发红包和转账到零钱账户,上一篇文章详细讲解了使用发红包的过程,从公众号内的配置,到微信支付的配置,再到具体的类实现. 本篇主要讲解转账到零钱,具体的类 ...

  5. 实例:用C#.NET手把手教你做微信公众号开发(13)--事件消息处理之取消关注

    一.取消关注事件 用户在取消关注公众号时,微信会把这个事件推送到开发者填写的URL,方便开发者做帐号的解绑等处理. <xml><ToUserName><![CDATA[t ...

  6. 实例:用C#.NET手把手教你做微信公众号开发(12)--带参数二维码裂变推广

    为什么能裂变推广是营销学和心理学的范畴了,这里举个简单的例子来介绍.公众号有足以吸引粉丝的地方,要么是知识.要么是优惠.要么是服务,反正不同于其他人,能够吸引人关注:有了这个前提,怎么让更多的人知道这 ...

  7. 实例:用C#.NET手把手教你做微信公众号开发(11)--生成带参数二维码

    上一篇讲了普通关注的各种情景,接下来准备详细讲解带参数的二维码的应用实例.在下一篇详解之前,这里先介绍一下如何下载二维码.生成二维码表,为后续的应用做好准备. 为了满足用户渠道推广分析和用户帐号绑定等 ...

  8. 实例:用C#.NET手把手教你做微信公众号开发(10)--事件消息处理之关注公众号(普通关注)

    一.事件消息种类 在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者可以获取到该信息.其中,某些事件推送在发生后 ...

  9. 实例:用C#.NET手把手教你做微信公众号开发(6)--普通消息处理之视频、小视频

    本篇讲解微信客户端向公众号发送视频和小视频的处理方式. 视频消息常见应用: 在线教学: 基于公众号的定向类型小视频应用,类似于抖音.快手,但不用再安装app: 视频剪辑.特效添加,比如美颜: 其它视频 ...

最新文章

  1. 宏基因组合种树第292期—侧柏、樟子松,为祖国绿化做贡献
  2. 性能测试工具_磁盘性能测试工具fio
  3. 微信小程序-基于canvas画画涂鸦
  4. 北京市将持续扩大5G网络建设规模 超前布局6G
  5. NSTimer的使用
  6. Mongo_安装 centos
  7. 自定义控件+ViewPage+Fragment....各种收获
  8. 贝叶斯滤波和粒子滤波
  9. ps如何把自己的图与样机结合_样机在ps里面怎么用|ps怎么把图片放在书本样机图中...
  10. DVWA靶机安装(超详细教程)
  11. 高精度三维空间测量、定位与追踪(上)
  12. 微信授权登录(更新。。。)
  13. 读光驱时,提示“无法访问,函数不正确”错误提示
  14. DOOM3源码分析相关文章集合
  15. 什么是微信小程序什么是小程序微信小程序有什么优势
  16. windows10下wordcloud模块成功安装
  17. 10个jQuery Page Peel插件
  18. 验证码机制之验证码自动识别
  19. 数据驱动决策:BI在零售业的数据化管理
  20. [转载-FLUENT学习]流动仿真计算时湍流模型的选择

热门文章

  1. 光立方——电子制作的软件模拟
  2. 【ClickHouse】ClickHouse 实用语法
  3. 【系统分析师】系统配置与性能评价
  4. 毕业论文案例-LDA主题模型实现文本聚类
  5. C语言程序设计学习笔记:P5-循环控制
  6. 7080生化分析仪使用说明书—— 维护保养篇
  7. 计算机史话pdf百度云,学生应知科技知识·计算机史话.pdf
  8. 嵌入式开发前景怎么样?嵌入式开发有哪些优势?
  9. 鲜花电商花点时间完成亿元融资 官网域名为英文域名reflower.com.cn
  10. c4I开发语言,初探go-golang语言初体验uknn