ASP.NET实现QQ、微信、新浪微博OAuth2.0授权登录 原创
程序员文章站
2022-03-21 15:31:18
不管是腾讯还是新浪,查看他们的api,php都是有完整的接口,但对c#支持似乎都不是那么完善,都没有,腾讯是完全没有,新浪是提供第三方的,而且后期还不一定升级,nnd,用第...
不管是腾讯还是新浪,查看他们的api,php都是有完整的接口,但对c#支持似乎都不是那么完善,都没有,腾讯是完全没有,新浪是提供第三方的,而且后期还不一定升级,nnd,用第三方的动辄就一个类库,各种配置还必须按照他们约定的写,烦而且乱,索性自己写,后期的扩展也容易,看过接口后,开始以为很难,参考了几个源码之后发现也不是那么难,无非是get或post请求他们的接口获取返回值之类的,话不多说,这里只提供几个代码共参考,抛砖引玉了。。。
我这个写法的特点是,用到了session,使用对象实例化之后调用 login() 跳转到登录页面,在回调页面调用callback() 执行之后,可以从session也可以写独立的函数(如:getopenid())中获取access_token或用户的唯一标识,以方便做下一步的操作。所谓绑定就是把用户的唯一标识取出,插入数据库,和帐号绑定起来。
1.首先是所有oauth类的基类,放一些需要公用的方法
public abstract class baseoauth { public httprequest request = httpcontext.current.request; public httpresponse response = httpcontext.current.response; public httpsessionstate session = httpcontext.current.session; public abstract void login(); public abstract string callback(); #region 内部使用函数 /// <summary> /// 生成唯一随机串防csrf攻击 /// </summary> /// <returns></returns> protected string getstatecode() { random rand = new random(); string data = datetime.now.tostring("yyyymmddhhmmssffff") + rand.next(1, 0xf423f).tostring(); md5cryptoserviceprovider md5 = new md5cryptoserviceprovider(); byte[] md5byte = md5.computehash(utf8encoding.default.getbytes(data)); return bitconverter.tostring(md5byte).replace("-", ""); } /// <summary> /// get请求 /// </summary> /// <param name="url"></param> /// <returns></returns> protected string getrequest(string url) { httpwebrequest httpwebrequest = system.net.webrequest.create(url) as httpwebrequest; httpwebrequest.method = "get"; httpwebrequest.servicepoint.expect100continue = false; streamreader responsereader = null; string responsedata; try { responsereader = new streamreader(httpwebrequest.getresponse().getresponsestream()); responsedata = responsereader.readtoend(); } finally { httpwebrequest.getresponse().getresponsestream().close(); responsereader.close(); } return responsedata; } /// <summary> /// post请求 /// </summary> /// <param name="url"></param> /// <param name="postdata"></param> /// <returns></returns> protected string postrequest(string url, string postdata) { httpwebrequest httpwebrequest = system.net.webrequest.create(url) as httpwebrequest; httpwebrequest.method = "post"; httpwebrequest.servicepoint.expect100continue = false; httpwebrequest.contenttype = "application/x-www-form-urlencoded"; //写入post参数 streamwriter requestwriter = new streamwriter(httpwebrequest.getrequeststream()); try { requestwriter.write(postdata); } finally { requestwriter.close(); } //读取请求后的结果 streamreader responsereader = null; string responsedata; try { responsereader = new streamreader(httpwebrequest.getresponse().getresponsestream()); responsedata = responsereader.readtoend(); } finally { httpwebrequest.getresponse().getresponsestream().close(); responsereader.close(); } return responsedata; } /// <summary> /// 解析json /// </summary> /// <param name="strjson"></param> /// <returns></returns> protected namevaluecollection parsejson(string strjson) { namevaluecollection mc = new namevaluecollection(); regex regex = new regex(@"(\s*\""?([^""]*)\""?\s*\:\s*\""?([^""]*)\""?\,?)"); strjson = strjson.trim(); if (strjson.startswith("{")) { strjson = strjson.substring(1, strjson.length - 2); } foreach (match m in regex.matches(strjson)) { mc.add(m.groups[2].value, m.groups[3].value); } return mc; } /// <summary> /// 解析url /// </summary> /// <param name="strparams"></param> /// <returns></returns> protected namevaluecollection parseurlparameters(string strparams) { namevaluecollection nc = new namevaluecollection(); foreach (string p in strparams.split('&')) { string[] ps = p.split('='); nc.add(ps[0], ps[1]); } return nc; } #endregion }
2.qq的oauth类
public class qqoauth : baseoauth { public string appid = configurationmanager.appsettings["oauth_qq_appid"]; public string appkey = configurationmanager.appsettings["oauth_qq_appkey"]; public string redirecturl = configurationmanager.appsettings["oauth_qq_redirecturl"]; public const string get_auth_code_url = "https://graph.qq.com/oauth2.0/authorize"; public const string get_access_token_url = "https://graph.qq.com/oauth2.0/token"; public const string get_openid_url = "https://graph.qq.com/oauth2.0/me"; /// <summary> /// qq登录,跳转到登录页面 /// </summary> public override void login() { //-------生成唯一随机串防csrf攻击 string state = getstatecode(); session["qc_state"] = state; //state 放入session string parms = "?response_type=code&" + "client_id=" + appid + "&redirect_uri=" + uri.escapedatastring(redirecturl) + "&state=" + state; string url = get_auth_code_url + parms; response.redirect(url); //跳转到登录页面 } /// <summary> /// qq回调函数 /// </summary> /// <param name="code"></param> /// <param name="state"></param> /// <returns></returns> public override string callback() { string code = request.querystring["code"]; string state = request.querystring["state"]; //--------验证state防止csrf攻击 if (state != (string)session["qc_state"]) { showerror("30001"); } string parms = "?grant_type=authorization_code&" + "client_id=" + appid + "&redirect_uri=" + uri.escapedatastring(redirecturl) + "&client_secret=" + appkey + "&code=" + code; string url = get_access_token_url + parms; string str = getrequest(url); if (str.indexof("callback") != -1) { int lpos = str.indexof("("); int rpos = str.indexof(")"); str = str.substring(lpos + 1, rpos - lpos - 1); namevaluecollection msg = parsejson(str); if (!string.isnullorempty(msg["error"])) { showerror(msg["error"], msg["error_description"]); } } namevaluecollection token = parseurlparameters(str); session["qc_accesstoken"] = token["access_token"]; //access_token 放入session return token["access_token"]; } /// <summary> /// 使用access token来获取用户的openid /// </summary> /// <param name="accesstoken"></param> /// <returns></returns> public string getopenid() { string parms = "?access_token=" + session["qc_accesstoken"]; string url = get_openid_url + parms; string str = getrequest(url); if (str.indexof("callback") != -1) { int lpos = str.indexof("("); int rpos = str.indexof(")"); str = str.substring(lpos + 1, rpos - lpos - 1); } namevaluecollection user = parsejson(str); if (!string.isnullorempty(user["error"])) { showerror(user["error"], user["error_description"]); } session["qc_openid"] = user["openid"]; //openid 放入session return user["openid"]; } /// <summary> /// 显示错误信息 /// </summary> /// <param name="code">错误编号</param> /// <param name="description">错误描述</param> private void showerror(string code, string description = null) { if (description == null) { switch (code) { case "20001": description = "<h2>配置文件损坏或无法读取,请检查web.config</h2>"; break; case "30001": description = "<h2>the state does not match. you may be a victim of csrf.</h2>"; break; case "50001": description = "<h2>可能是服务器无法请求https协议</h2>可能未开启curl支持,请尝试开启curl支持,重启web服务器,如果问题仍未解决,请联系我们"; break; default: description = "<h2>系统未知错误,请联系我们</h2>"; break; } response.write(description); response.end(); } else { response.write("<h3>error:<h3>" + code + "<h3>msg:<h3>" + description); response.end(); } } }
3.新浪微博的oauth类
public class sinaoauth : baseoauth { public string appkey = configurationmanager.appsettings["oauth_sina_appkey"]; public string appsecret = configurationmanager.appsettings["oauth_sina_appsecret"]; public string redirecturl = configurationmanager.appsettings["oauth_sina_redirecturl"]; public const string get_auth_code_url = "https://api.weibo.com/oauth2/authorize"; public const string get_access_token_url = "https://api.weibo.com/oauth2/access_token"; public const string get_uid_url = "https://api.weibo.com/2/account/get_uid.json"; /// <summary> /// 新浪微博登录,跳转到登录页面 /// </summary> public override void login() { //-------生成唯一随机串防csrf攻击 string state = getstatecode(); session["sina_state"] = state; //state 放入session string parms = "?client_id=" + appkey + "&redirect_uri=" + uri.escapedatastring(redirecturl) + "&state=" + state; string url = get_auth_code_url + parms; response.redirect(url); //跳转到登录页面 } /// <summary> /// 新浪微博回调函数 /// </summary> /// <returns></returns> public override string callback() { string code = request.querystring["code"]; string state = request.querystring["state"]; //--------验证state防止csrf攻击 if (state != (string)session["sina_state"]) { showerror("the state does not match. you may be a victim of csrf."); } string parms = "client_id=" + appkey + "&client_secret=" + appsecret + "&grant_type=authorization_code&code=" + code + "&redirect_uri=" + uri.escapedatastring(redirecturl); string str = postrequest(get_access_token_url, parms); namevaluecollection user = parsejson(str); session["sina_accesstoken"] = user["access_token"]; //access_token 放入session session["sina_uid"] = user["uid"]; //uid 放入session return user["access_token"]; } /// <summary> /// 显示错误信息 /// </summary> /// <param name="description">错误描述</param> private void showerror(string description = null) { response.write("<h2>" + description + "</h2>"); response.end(); } }
4.微信的oauth类
public class weixinoauth : baseoauth { public string appid = configurationmanager.appsettings["oauth_weixin_appid"]; public string appsecret = configurationmanager.appsettings["oauth_weixin_appsecret"]; public string redirecturl = configurationmanager.appsettings["oauth_weixin_redirecturl"]; public const string get_auth_code_url = "https://open.weixin.qq.com/connect/qrconnect"; public const string get_access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token"; public const string get_userinfo_url = "https://api.weixin.qq.com/sns/userinfo"; /// <summary> /// 微信登录,跳转到登录页面 /// </summary> public override void login() { //-------生成唯一随机串防csrf攻击 string state = getstatecode(); session["weixin_state"] = state; //state 放入session string parms = "?appid=" + appid + "&redirect_uri=" + uri.escapedatastring(redirecturl) + "&response_type=code&scope=snsapi_login" + "&state=" + state + "#wechat_redirect"; string url = get_auth_code_url + parms; response.redirect(url); //跳转到登录页面 } /// <summary> /// 微信回调函数 /// </summary> /// <param name="code"></param> /// <param name="state"></param> /// <returns></returns> public override string callback() { string code = request.querystring["code"]; string state = request.querystring["state"]; //--------验证state防止csrf攻击 if (state != (string)session["weixin_state"]) { showerror("30001"); } string parms = "?appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=authorization_code"; string url = get_access_token_url + parms; string str = getrequest(url); namevaluecollection msg = parsejson(str); if (!string.isnullorempty(msg["errcode"])) { showerror(msg["errcode"], msg["errmsg"]); } session["weixin_accesstoken"] = msg["access_token"]; //access_token 放入session session["weixin_openid"] = msg["openid"]; //access_token 放入session return msg["access_token"]; } /// <summary> /// 显示错误信息 /// </summary> /// <param name="code">错误编号</param> /// <param name="description">错误描述</param> private void showerror(string code, string description = null) { if (description == null) { switch (code) { case "20001": description = "<h2>配置文件损坏或无法读取,请检查web.config</h2>"; break; case "30001": description = "<h2>the state does not match. you may be a victim of csrf.</h2>"; break; case "50001": description = "<h2>接口未授权</h2>"; break; default: description = "<h2>系统未知错误,请联系我们</h2>"; break; } response.write(description); response.end(); } else { response.write("<h3>error:<h3>" + code + "<h3>msg:<h3>" + description); response.end(); } } }
5.web.config配置信息
<appsettings> <!--qq登录相关配置--> <add key="oauth_qq_appid" value="123456789" /> <add key="oauth_qq_appkey" value="25f9e794323b453885f5181f1b624d0b" /> <add key="oauth_qq_redirecturl" value="http://www.domain.com/oauth20/qqcallback.aspx" /> <!--新浪微博登录相关配置--> <add key="oauth_sina_appkey" value="123456789" /> <add key="oauth_sina_appsecret" value="25f9e794323b453885f5181f1b624d0b" /> <add key="oauth_sina_redirecturl" value="http://www.domain.com/oauth20/sinacallback.aspx" /> <!--微信登录相关配置--> <add key="oauth_weixin_appid" value="wx123456789123" /> <add key="oauth_weixin_appsecret" value="25f9e794323b453885f5181f1b624d0b" /> <add key="oauth_weixin_redirecturl" value="http://www.domain.com/oauth20/weixincallback.aspx" /> </appsettings>
推荐阅读
-
第三方OAuth授权登录,QQ、微信(WeChat)、微博、GitHub、码云(Gitee)、淘宝(天猫)、微软(Microsoft )、钉钉、谷歌(Google)、支付宝(AliPay)、*
-
js实现QQ、微信、新浪微博分享功能
-
ASP.NET实现QQ、微信、新浪微博OAuth2.0授权登录 原创
-
js实现QQ、微信、新浪微博分享功能
-
网页授权登录有关问题, 怎么可以长期登录, 用qq,新浪微博登录
-
网页授权登录有关问题, 怎么可以长期登录, 用qq,新浪微博登录
-
ASP.NET实现QQ、微信、新浪微博OAuth2.0授权登录的实例详解
-
第三方OAuth授权登录,QQ、微信(WeChat)、微博、GitHub、码云(Gitee)、淘宝(天猫)、微软(Microsoft )、钉钉、谷歌(Google)、支付宝(AliPay)、*
-
Laravel5.1 实现第三方登录认证(包括微博、QQ、微信、豆瓣)
-
ASP.NET实现QQ、微信、新浪微博OAuth2.0授权登录的实例详解