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

注意:网页授权两种方式

更多网页授权请查阅官网文档:网页授权
静默授权
静默授权即可以在用户关注的的时候,获取用户基本信息,此过程用户无感知。
第一步,通过工厂类 转发请求
/// <returns></returns>
public string HandleRequest()
{
string response = string.Empty;
EventMessage em = EventMessage.LoadFromXml(RequestXml);
if (em != null)
{
switch (em.Event.ToLower())
{
case ("subscribe"):
response = SubscribeEventHandler(em);//通过工厂类分发过来的请求,匹配到关注事件
break;
case ("unsubscribe"):
response = Un_SubscribeEventHandler(em);
break;
case "click":
response = ClickEventHandler(em);
break;
}
}
return response;
}第二步,写用户关注事件
/// <summary>
/// 用户关注
/// </summary>
/// <param name="em"></param>
/// <returns></returns>
public string SubscribeEventHandler(EventMessage em)
{
//回复欢迎消息
WeChat.Messages.TextMessage tm = new WeChat.Messages.TextMessage();
tm.ToUserName = em.FromUserName;//OpenId
tm.FromUserName = em.ToUserName;//公众号原始Id
tm.CreateTime = Common.GetNowTime();
tm.Content = "欢迎您关注****,我是服务小二,有事就问我~
";
tm.GenerateContent();
//如有业务需要,可在此处先判断该用户是否已关注
//此处得到OpenId
show.ShowUserInfo(em.FromUserName,em.ToUserName);
return tm.GenerateContent();
}第三步,根据得到的OpenId及accesstoken,即可获取用户基本信息(此处演示是将该用户存入数据库中)
/// <summary>
/// 根据OpenId将此条粉丝记录插入数据库中
/// </summary>
/// <param name="FromUserName"></param>
/// <param name="ToUserName"></param>
public void ShowUserInfo(string FromUserName, string ToUserName)
{
try
{
Models.Users user = new Models.Users();
DAL.User userInfo = new DAL.User();
//获取accesstoken,获取用户基本信息需要Openid和accesstoken即可
accesstoken = Utility.Context.AccessToken;
string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", accesstoken, FromUserName);
string result = HttpUtility.GetData(url);
XDocument doc = XmlUtility.ParseJson(result, "root");
XElement root = doc.Root;
if (root != null)
{
#region 取值/存值
subscribe = root.Element("subscribe").Value;//是否关注 1 是关注
nickname = root.Element("nickname").Value; //昵称
sex = root.Element("sex").Value; //性别什么
headimgurl = root.Element("headimgurl").Value; //头像url
province = root.Element("province").Value;//地区
country = root.Element("country").Value;
language = root.Element("language").Value;
subscribe_time = root.Element("subscribe_time").Value;
DateTime create_time = Common.GetTime(subscribe_time);//将时间戳转换为当前时间
city = root.Element("city").Value;
user.OpenID = FromUserName;//OpenID即粉丝ID
user.PublicId = ToUserName;
user.UserID = FromUserName;
user.NickName = nickname;
user.Sex = int.Parse(sex);
user.Subscribe = int.Parse(subscribe);
user.Country = country;
user.Province = province;
user.City = city;
user.CreateDate = create_time;
user.HeadimgUrl = headimgurl;
//将user实体存入数据库中
bool show = _user.Add(user);
#endregion
}
}
catch
{
throw (new ArgumentNullException());
}
}上面代码中 AccessToken的实现,新建一个Context类即可
private static DateTime GetAccessToken_Time;
/// <summary>
/// 过期时间为7200秒
/// </summary>
private static int Expires_Period = 7200;
/// <summary>
///
/// </summary>
private static string mAccessToken;
public static string AppID = "换成相应公众号的即可";
public static string AppSecret = "换成相应公众号的即可";
/// <summary>
/// 调用获取ACCESS_TOKEN,包含判断是否过期
/// </summary>
public static string AccessToken
{
get
{
//如果为空,或者过期,需要重新获取
if (string.IsNullOrEmpty(mAccessToken) || HasExpired())
{
//获取access_token
mAccessToken = GetAccessToken(AppID, AppSecret);
}
return mAccessToken;
}
}
/// <summary>
/// 获取ACCESS_TOKEN方法
/// </summary>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <returns></returns>
private static string GetAccessToken(string appId, string appSecret)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appSecret);
string result = HttpUtility.GetData(url);
XDocument doc = XmlUtility.ParseJson(result, "root");
XElement root = doc.Root;
if (root != null)
{
XElement access_token = root.Element("access_token");
if (access_token != null)
{
GetAccessToken_Time = DateTime.Now;
if (root.Element("expires_in") != null)
{
Expires_Period = int.Parse(root.Element("expires_in").Value);
}
return access_token.Value;
}
else
{
GetAccessToken_Time = DateTime.MinValue;
}
}
return null;
}
/// <summary>
/// 判断Access_token是否过期
/// </summary>
/// <returns>bool</returns>
private static bool HasExpired()
{
if (GetAccessToken_Time != null)
{
//过期时间,允许有一定的误差,一分钟。获取时间消耗
if (DateTime.Now > GetAccessToken_Time.AddSeconds(Expires_Period).AddSeconds(-60))
{
return true;
}
}
return false;
}GetData的实现
public static string GetData(string url)
{
return SendGetHttpRequest(url, "application/x-www-form-urlencoded");
}
ParseJson的实现
public static XDocument ParseJson(string json, string rootName)
{
return JsonConvert.DeserializeXNode(json, rootName);
}关于第三步的 HttpUtility类中还有一些其他公用帮助方法,在这里一并放出,调用即可

View Code
顺便提下上文中用到的User类如下
public class Users
{
/// <summary>
/// 全局凭证唯一Id
/// </summary>
public string OpenID { get; set; }
/// <summary>
/// 公众号Id
/// </summary>
public string PublicId { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public string UserID { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 性别 1是男 0是女
/// </summary>
public int Sex { get; set; }
/// <summary>
/// 是否关注 1是关注
/// </summary>
public int Subscribe { get; set; }
/// <summary>
/// 国家
/// </summary>
public string Country { get; set; }
/// <summary>
/// 地区
/// </summary>
public string Province { get; set; }
/// <summary>
/// 城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 关注时间
/// </summary>
public DateTime CreateDate { get; set; }
/// <summary>
/// 用户头像
/// </summary>
public string HeadimgUrl { get; set; }
/// <summary>
/// 第三方平台Id,可为空
/// </summary>
public string UnionID { get; set; }
/// <summary>
/// 用户取消关注时间
/// </summary>
public DateTime Un_Subscribe_Time { get; set; }
}演示效果
数据库中此时是存在10条数据的,当点击关注此公众号的时候,就将此用户的基本信息存入数据库了,数据库刷新后变成11条数据


网页授权流程

具体介绍依然可参考官网文档:网页授权
第一步,判断该用户是否获取授权,若没有授权,则跳转至授权页面,若授权,则获取基本信息
核心代码
/// <summary>
/// 获取授权用户的基本信息,包括头像,姓名,等等(推荐方法)
/// </summary>
/// <param name="accessToken">用户授权之后的accessToken</param>
/// <param name="openid">用户授权之后的openid</param>
/// <returns></returns>
public static ShouQuanWeiXinUserInfo GetShouQuanMessage()
{
//先判断是否有获取到用户授权的Code,HttpContext.Current.Session["ShouquanCode"]
if (HttpContext.Current.Session["ShouquanCode"] == null|| HttpContext.Current.Session["ShouquanCode"].ToString()=="")
{
HttpContext.Current.Session["ShouquanCode"] = "123";
//用户授权的Code
GetShouQuanCodeUrl(HttpContext.Current.Request.Url.AbsoluteUri);
}
else if(HttpContext.Current.Request.QueryString["code"] == null || HttpContext.Current.Request.QueryString["code"] == "")
{
//用户授权的Code
GetShouQuanCodeUrl(HttpContext.Current.Request.Url.AbsoluteUri);
}
else
{
var model = ShouQuanAccessToken(HttpContext.Current.Request.QueryString["code"]);
var url =
$"https://api.weixin.qq.com/sns/userinfo?access_token={model.access_token}&openid={model.openid}&lang=zh_CN";
string gethtml = MyHttpHelper.HttpGet(url);
var ac = JsonHelpers.ToObject<ShouQuanWeiXinUserInfo>(gethtml);
return ac;
}
return null;
}其中,用户授权的code方法如下:
/// <summary>
/// 重新获取用户授权的Code,可以获取用户的基本信息(头像,姓名,等等)(推荐用的方法)
/// </summary>
/// <param name="url">目标Url</param>
/// <returns></returns>
public static void GetShouQuanCodeUrl(string url)
{
string CodeUrl = "";
//加密过的url
string value = HttpUtility.UrlEncode(url);
//用户授权后的Code
CodeUrl = $"https://open.weixin.qq.com/connect/oauth2/authorize?appid={Appid}&redirect_uri={value}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
System.Web.HttpContext.Current.Response.Redirect(CodeUrl);//先跳转到微信的服务器,取得code后会跳回来这页面的
}其中ShouQuanAccessToken方法
/// <summary>
//用户授权之后,获取授权的Access_Token与基本的Access_Token是不同的(推荐方法)
/// </summary>
/// <param name="code">用户授权之后的Code</param>
/// <returns></returns>
public static OauthAccessToken ShouQuanAccessToken(string code)
{
var url = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={Appid}&secret={Secret}&code={code}&grant_type=authorization_code";
string gethtml = MyHttpHelper.HttpGet(url);
OauthAccessToken ac = new OauthAccessToken();
ac = JsonHelpers.ToObject<OauthAccessToken>(gethtml);
return ac;
}用户实体
public class OauthAccessToken
{
public string access_token { get; set; }
public string expires_in { get; set; }
public string refresh_token { get; set; }
public string openid { get; set; }
public string scope { get; set; }
}其中用到的MyHttpHelper公众类如下

View Code
封装的JsonHelpers类如下

View Code
其中,如果是VS2015以下的,可以将url字符串改成string.format("")方式
调用取值的方式

效果展示
点击公众号链接效果如下:

未完待续,持续填坑中。。。
__EOF__
原作 者:潇十一郎
版权所有:原作者
出 处:http://www.cnblogs.com/zhangxiaoyong/p/6270768.html