网站改标题不改版 k,招聘网站建设价格,seo优化一般多少钱,网站建设合同书缴纳印花税吗目录
微信网页授权能力调整造成的问题
能力调整的内容和理由
原有运行方案
is_snapshotuser字段
改造原有方案
如何复现测试场景
小结 微信网页授权能力调整造成的问题
依附于第三方的开发#xff0c;做为开发者经常会遇到第三方进行规范和开发的调整#xff0c;如开…目录
微信网页授权能力调整造成的问题
能力调整的内容和理由
原有运行方案
is_snapshotuser字段
改造原有方案
如何复现测试场景
小结 微信网页授权能力调整造成的问题
依附于第三方的开发做为开发者经常会遇到第三方进行规范和开发的调整如开发腾讯微信的相关应用。我所经历的如小程序隐私政策调整、信息备案调整、微信授权获取个人信息限制调整等。
最近我们的一些项目因为微信页面授权能力的调整出现了一些问题对于新用户未经授权前微信开发团队给出的输出是快照页该页内所获取的openId等均为虚拟账号数据并在屏幕下方非常不明显的显示“使用完整服务”如下图所示 此图即是微信给出的授权提示也是我们折中的解决方案图中所示的提示框源自己于我们通过携带的参数反馈给用户的提示以引导用户点击下方的“使用完整服务”链接并进行授权。
能力调整的内容和理由
微信团队给出的解释是当开发者在网页中在不规范使用发起 snsapi_userinfo 网页授权时微信将默认打开网页快照页模式进行基础浏览。
微信网页授权规范
授权流程需引导清晰、准确在申请获取用户信息的弹窗出现前应该清晰、准确地告知用户获取信息的范围及获取信息的目的必要场景申请在必须获取用户信息时才申请而不是用户尚未了解服务前就强制弹窗。如使用医院挂号时才需要获取用户信息不强制登录提供游客模式供用户了解网页提供的基础服务不强制用户允许网页获取用户信息后才能使用网页服务。
常见的微信网页授权不规范使用案例
强制登录在用户打开网页时立即要求用户授权用户拒绝后无法使用网页提供的服务违规收集个人信息未在网页提前告知使用个人信息的目的、方式和范围非必要收集非必要获取用户信息的网页如文章、视频等要求用户在浏览内容前登录差别对待微信用户同样的网页在浏览器内可以无需登录直接访问在微信内却要求用户先登录才可访问。
原有运行方案
微信OA2授权访问地址如下(示例url为C#字符串)
https://open.weixin.qq.com/connect/oauth2/authorize?appidwx7964497eb8bad783amp;redirect_urihttps%3A//www.leadihr.com/weixin/oa2.aspx%3Famp;response_typecodeamp;scopesnsapi_userinfoamp;state1#wechat_redirectamp;connect_redirect 1
重定向接收地址 OA2.ASPX程序 C#版本
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Collections;
using System.Net;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using LitJson;
using System.Data;
using System.Data.SqlClient;
using CosysJaneCommonAPI;
using System.Web.Script.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;public partial class oa2 : System.Web.UI.Page
{string Appid ;string appsecret ;string domain ;public class OAuth_Token{public OAuth_Token(){}//access_token 网页授权接口调用凭证,注意此access_token与基础支持的access_token不同 //expires_in access_token接口调用凭证超时时间单位秒 //refresh_token 用户刷新access_token //openid 用户唯一标识请注意在未关注公众号时用户访问公众号的网页也会产生一个用户和公众号唯一的OpenID //scope 用户授权的作用域使用逗号,分隔 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; }}public class OAuthUser{public OAuthUser(){ }#region 数据库字段private string _openID;private string _searchText;private string _unionid;private string _nickname;private string _sex;private string _province;private string _city;private string _country;private string _headimgUrl;
// private string _privilege;#endregion#region 字段属性/// summary /// 用户的唯一标识 /// /summary public string openid{set { _openID value; }get { return _openID; }}public string SearchText{set { _searchText value; }get { return _searchText; }}/// summary /// 用户昵称 /// /summary public string nickname{set { _nickname value; }get { return _nickname; }}public string unionid{set { _unionid value; }get { return _unionid; }}/// summary /// 用户的性别值为1时是男性值为2时是女性值为0时是未知 /// /summary public string sex{set { _sex value; }get { return _sex; }}/// summary /// 用户个人资料填写的省份 /// /summary public string province{set { _province value; }get { return _province; }}/// summary /// 普通用户个人资料填写的城市 /// /summary public string city{set { _city value; }get { return _city; }}/// summary /// 国家如中国为CN /// /summary public string country{set { _country value; }get { return _country; }}/// summary /// 用户头像最后一个数值代表正方形头像大小有0、46、64、96、132数值可选0代表640*640正方形头像用户没有头像时该项为空 /// /summary public string headimgurl{set { _headimgUrl value; }get { return _headimgUrl; }}/// summary /// 用户特权信息json 数组如微信沃卡用户为chinaunicom其实这个格式称不上JSON只是个单纯数组 /// /summary //public string privilege//{// set { _privilege value; }// get { return _privilege; }//}#endregion} protected void Page_Load(object sender, EventArgs e) {if (!IsPostBack) {if (!string.IsNullOrEmpty(Request.QueryString[code])) { string Code Request.QueryString[code].ToString();string State Request.QueryString[state].ToString();//获得Token OAuth_Token Model Get_token(Code);OAuthUser OAuthUser_Model Get_UserInfo(Model.access_token, Model.openid);string contentModel.access_token 用户OPENID: OAuthUser_Model.openid br用户昵称: OAuthUser_Model.nickname br性别: OAuthUser_Model.sex br所在省: OAuthUser_Model.province br所在市: OAuthUser_Model.city br所在国家: OAuthUser_Model.country br头像地址: OAuthUser_Model.headimgurl br用户特权信息:;Response.Redirect(https://x.x.com/index.aspx?oid OAuthUser_Model.openid);} } }
public class JsonHelper
{/// summary/// 生成Json格式/// /summary/// typeparam nameT/typeparam/// param nameobj/param/// returns/returnspublic static string GetJsonT(T obj){DataContractJsonSerializer json new DataContractJsonSerializer(obj.GetType());using (MemoryStream stream new MemoryStream()){json.WriteObject(stream, obj);string szJson Encoding.UTF8.GetString(stream.ToArray()); return szJson;}}/// summary/// 获取Json的Model/// /summary/// typeparam nameT/typeparam/// param nameszJson/param/// returns/returnspublic static T ParseFromJsonT(string szJson){T obj Activator.CreateInstanceT();using (MemoryStream ms new MemoryStream(Encoding.UTF8.GetBytes(szJson))){DataContractJsonSerializer serializer new DataContractJsonSerializer(obj.GetType());return (T)serializer.ReadObject(ms);}}
} //获得Token protected OAuth_Token Get_token(string Code) { string Str GetJson(https://api.weixin.qq.com/sns/oauth2/access_token?appid Appid secret appsecret code Code grant_typeauthorization_code);OAuth_Token Oauth_Token_Model JsonHelper.ParseFromJsonOAuth_Token(Str); return Oauth_Token_Model; } //刷新Token protected OAuth_Token refresh_token(string REFRESH_TOKEN) { string Str GetJson(https://api.weixin.qq.com/sns/oauth2/refresh_token?appid Appid grant_typerefresh_tokenrefresh_token REFRESH_TOKEN); OAuth_Token Oauth_Token_Model JsonHelper.ParseFromJsonOAuth_Token(Str); return Oauth_Token_Model; } //获得用户信息 protected OAuthUser Get_UserInfo(string REFRESH_TOKEN, string OPENID) { // Response.Write(获得用户信息REFRESH_TOKEN: REFRESH_TOKEN ||OPENID: OPENID); string Str GetJson(https://api.weixin.qq.com/sns/userinfo?access_token REFRESH_TOKEN openid OPENID langzh_CN); OAuthUser OAuthUser_Model JsonHelper.ParseFromJsonOAuthUser(Str);return OAuthUser_Model; } protected string GetJson(string url) { WebClient wc new WebClient(); wc.Credentials CredentialCache.DefaultCredentials; wc.Encoding Encoding.UTF8;string returnText ;try{returnText wc.DownloadString(url);}catch (Exception e){Response.Write(e.Message);Response.End();}if (returnText.Contains(errcode)) { //可能发生错误 } //Response.Write(returnText); return returnText; } }
is_snapshotuser字段
通过code换取网页授权access_token 请求方法是获取code后请求以下链接获取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appidAPPIDsecretSECRETcodeCODEgrant_typeauthorization_code
正确时会返回具有如下图所示的JSON数据包 因此可能通过判断 is_snapshotuser 字段是否为1判断是否快照页模式
改造原有方案
主要是增加 string is_snapshotuser 0 和后续对JSON返回值的判断并返回回调的url并携带此参数。示例代码如下
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Collections;
using System.Net;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using LitJson;
using System.Data;
using System.Data.SqlClient;
using CosysJaneCommonAPI;
using System.Web.Script.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;public partial class oa2 : System.Web.UI.Page
{string Appid ;string appsecret ;string domain ;string is_snapshotuser 0;public class OAuth_Token{public OAuth_Token(){}//access_token 网页授权接口调用凭证,注意此access_token与基础支持的access_token不同 //expires_in access_token接口调用凭证超时时间单位秒 //refresh_token 用户刷新access_token //openid 用户唯一标识请注意在未关注公众号时用户访问公众号的网页也会产生一个用户和公众号唯一的OpenID //scope 用户授权的作用域使用逗号,分隔 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; }}public class OAuthUser{public OAuthUser(){ }#region 数据库字段private string _openID;private string _searchText;private string _unionid;private string _nickname;private string _sex;private string _province;private string _city;private string _country;private string _headimgUrl;
// private string _privilege;#endregion#region 字段属性/// summary /// 用户的唯一标识 /// /summary public string openid{set { _openID value; }get { return _openID; }}public string SearchText{set { _searchText value; }get { return _searchText; }}/// summary /// 用户昵称 /// /summary public string nickname{set { _nickname value; }get { return _nickname; }}public string unionid{set { _unionid value; }get { return _unionid; }}/// summary /// 用户的性别值为1时是男性值为2时是女性值为0时是未知 /// /summary public string sex{set { _sex value; }get { return _sex; }}/// summary /// 用户个人资料填写的省份 /// /summary public string province{set { _province value; }get { return _province; }}/// summary /// 普通用户个人资料填写的城市 /// /summary public string city{set { _city value; }get { return _city; }}/// summary /// 国家如中国为CN /// /summary public string country{set { _country value; }get { return _country; }}/// summary /// 用户头像最后一个数值代表正方形头像大小有0、46、64、96、132数值可选0代表640*640正方形头像用户没有头像时该项为空 /// /summary public string headimgurl{set { _headimgUrl value; }get { return _headimgUrl; }}/// summary /// 用户特权信息json 数组如微信沃卡用户为chinaunicom其实这个格式称不上JSON只是个单纯数组 /// /summary //public string privilege//{// set { _privilege value; }// get { return _privilege; }//}#endregion} protected void Page_Load(object sender, EventArgs e) {if (!IsPostBack) {if (!string.IsNullOrEmpty(Request.QueryString[code])) { string Code Request.QueryString[code].ToString();string State Request.QueryString[state].ToString();//获得Token OAuth_Token Model Get_token(Code);OAuthUser OAuthUser_Model Get_UserInfo(Model.access_token, Model.openid);string contentModel.access_token 用户OPENID: OAuthUser_Model.openid br用户昵称: OAuthUser_Model.nickname br性别: OAuthUser_Model.sex br所在省: OAuthUser_Model.province br所在市: OAuthUser_Model.city br所在国家: OAuthUser_Model.country br头像地址: OAuthUser_Model.headimgurl br用户特权信息:;Response.Redirect(https://x.x.com/index.aspx?oid OAuthUser_Model.openidis_snapshotuseris_snapshotuser);} } }
public class JsonHelper
{/// summary/// 生成Json格式/// /summary/// typeparam nameT/typeparam/// param nameobj/param/// returns/returnspublic static string GetJsonT(T obj){DataContractJsonSerializer json new DataContractJsonSerializer(obj.GetType());using (MemoryStream stream new MemoryStream()){json.WriteObject(stream, obj);string szJson Encoding.UTF8.GetString(stream.ToArray()); return szJson;}}/// summary/// 获取Json的Model/// /summary/// typeparam nameT/typeparam/// param nameszJson/param/// returns/returnspublic static T ParseFromJsonT(string szJson){T obj Activator.CreateInstanceT();using (MemoryStream ms new MemoryStream(Encoding.UTF8.GetBytes(szJson))){DataContractJsonSerializer serializer new DataContractJsonSerializer(obj.GetType());return (T)serializer.ReadObject(ms);}}
} //获得Token protected OAuth_Token Get_token(string Code) { string Str GetJson(https://api.weixin.qq.com/sns/oauth2/access_token?appid Appid secret appsecret code Code grant_typeauthorization_code);if (Str.IndexOf(\is_snapshotuser\:1) ! -1||Str.IndexOf(\is_snapshotuser\: 1)!-1){is_snapshotuser 1;}OAuth_Token Oauth_Token_Model JsonHelper.ParseFromJsonOAuth_Token(Str); return Oauth_Token_Model; } //刷新Token protected OAuth_Token refresh_token(string REFRESH_TOKEN) { string Str GetJson(https://api.weixin.qq.com/sns/oauth2/refresh_token?appid Appid grant_typerefresh_tokenrefresh_token REFRESH_TOKEN); OAuth_Token Oauth_Token_Model JsonHelper.ParseFromJsonOAuth_Token(Str); return Oauth_Token_Model; } //获得用户信息 protected OAuthUser Get_UserInfo(string REFRESH_TOKEN, string OPENID) { // Response.Write(获得用户信息REFRESH_TOKEN: REFRESH_TOKEN ||OPENID: OPENID); string Str GetJson(https://api.weixin.qq.com/sns/userinfo?access_token REFRESH_TOKEN openid OPENID langzh_CN); OAuthUser OAuthUser_Model JsonHelper.ParseFromJsonOAuthUser(Str);return OAuthUser_Model; } protected string GetJson(string url) { WebClient wc new WebClient(); wc.Credentials CredentialCache.DefaultCredentials; wc.Encoding Encoding.UTF8;string returnText ;try{returnText wc.DownloadString(url);}catch (Exception e){Response.Write(e.Message);Response.End();}if (returnText.Contains(errcode)) { //可能发生错误 } //Response.Write(returnText); return returnText; } }
这样可以在业务页面如上述代码中的index.aspx进行如下判断
if (Request.QueryString[is_snapshotuser] 1)
{Layer.open(使用前微信要求您的授权请点击下方使用完整服务后继续..., 确定, info);return;
}
如何复现测试场景
已经授权的用户如果想测试重新授权的场景请打开微信依如下步骤进行设置 小结
以上示例是一种较小改动的解决方案个人比较习惯于应用程序稳定性第一的思路。如果已经使用新规则设计方案则可仅供参考。
另外在此介绍一下关于网页授权的两种scope的区别 1、以snsapi_base为scope发起的网页授权可以直接获取进入页面的用户的openid且是静默授权并自动跳转到业务页面。 2、以snsapi_userinfo为scope发起的网页授权是用来获取用户的基本信息的。需要用户手动同意无须关注就可在授权后获取该用户的基本信息。
以上是个人的一些观点和解决方案感谢阅读并提出指正。