小依,薛城房屋出租,韩宫窥春
工具:
visual studio 2015 update 3
asp.net core 1.0
1 准备工作
申请微信公众平台接口测试帐号,申请网址:(http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login)。申请接口测试号无需公众帐号,可以直接体验和测试公众平台所有高级接口。
1.1 配置接口信息
1.2 修改网页授权信息
点击“修改”后在弹出页面填入你的网站域名:
2 新建网站项目
2.1 选择asp.net core web application 模板
2.2 选择web 应用程序,并更改身份验证为个人用户账户
3 集成微信登录功能
3.1添加引用
打开project.json文件,添加引用microsoft.aspnetcore.authentication.oauth
3.2 添加代码文件
在项目中新建文件夹,命名为wechatoauth,并添加代码文件(本文最后附全部代码)。
3.3 注册微信登录中间件
打开startup.cs文件,在configure中添加代码:
app.usewechatauthentication(new wechatoptions() { appid = "******", appsecret = "******" });
注意该代码的插入位置必须在app.useidentity()下方。
4 代码
:
// copyright (c) .net foundation. all rights reserved. // licensed under the apache license, version 2.0. see license.txt in the project root for license information. using system; using microsoft.aspnetcore.authentication.wechat; using microsoft.extensions.options; namespace microsoft.aspnetcore.builder { /// <summary> /// extension methods to add wechat authentication capabilities to an http application pipeline. /// </summary> public static class wechatappbuilderextensions { /// <summary> /// adds the <see cref="wechatmiddleware"/> middleware to the specified <see cref="iapplicationbuilder"/>, which enables wechat authentication capabilities. /// </summary> /// <param name="app">the <see cref="iapplicationbuilder"/> to add the middleware to.</param> /// <returns>a reference to this instance after the operation has completed.</returns> public static iapplicationbuilder usewechatauthentication(this iapplicationbuilder app) { if (app == null) { throw new argumentnullexception(nameof(app)); } return app.usemiddleware<wechatmiddleware>(); } /// <summary> /// adds the <see cref="wechatmiddleware"/> middleware to the specified <see cref="iapplicationbuilder"/>, which enables wechat authentication capabilities. /// </summary> /// <param name="app">the <see cref="iapplicationbuilder"/> to add the middleware to.</param> /// <param name="options">a <see cref="wechatoptions"/> that specifies options for the middleware.</param> /// <returns>a reference to this instance after the operation has completed.</returns> public static iapplicationbuilder usewechatauthentication(this iapplicationbuilder app, wechatoptions options) { if (app == null) { throw new argumentnullexception(nameof(app)); } if (options == null) { throw new argumentnullexception(nameof(options)); } return app.usemiddleware<wechatmiddleware>(options.create(options)); } } }
wechatdefaults.cs:
// copyright (c) .net foundation. all rights reserved. // licensed under the apache license, version 2.0. see license.txt in the project root for license information. namespace microsoft.aspnetcore.authentication.wechat { public static class wechatdefaults { public const string authenticationscheme = "wechat"; public static readonly string authorizationendpoint = "https://open.weixin.qq.com/connect/oauth2/authorize"; public static readonly string tokenendpoint = "https://api.weixin.qq.com/sns/oauth2/access_token"; public static readonly string userinformationendpoint = "https://api.weixin.qq.com/sns/userinfo"; } }
wechathandler.cs
// copyright (c) .net foundation. all rights reserved. // licensed under the apache license, version 2.0. see license.txt in the project root for license information. using microsoft.aspnetcore.authentication.oauth; using microsoft.aspnetcore.builder; using microsoft.aspnetcore.http.authentication; using microsoft.aspnetcore.http.extensions; using microsoft.extensions.primitives; using newtonsoft.json.linq; using system; using system.collections.generic; using system.net.http; using system.net.http.headers; using system.security.claims; using system.text; using microsoft.aspnetcore.mvc; using system.threading.tasks; namespace microsoft.aspnetcore.authentication.wechat { internal class wechathandler : oauthhandler<wechatoptions> { public wechathandler(httpclient httpclient) : base(httpclient) { } protected override async task<authenticateresult> handleremoteauthenticateasync() { authenticationproperties properties = null; var query = request.query; var error = query["error"]; if (!stringvalues.isnullorempty(error)) { var failuremessage = new stringbuilder(); failuremessage.append(error); var errordescription = query["error_description"]; if (!stringvalues.isnullorempty(errordescription)) { failuremessage.append(";description=").append(errordescription); } var erroruri = query["error_uri"]; if (!stringvalues.isnullorempty(erroruri)) { failuremessage.append(";uri=").append(erroruri); } return authenticateresult.fail(failuremessage.tostring()); } var code = query["code"]; var state = query["state"]; var oauthstate = query["oauthstate"]; properties = options.statedataformat.unprotect(oauthstate); if (state != options.stateaddition || properties == null) { return authenticateresult.fail("the oauth state was missing or invalid."); } // oauth2 10.12 csrf if (!validatecorrelationid(properties)) { return authenticateresult.fail("correlation failed."); } if (stringvalues.isnullorempty(code)) { return authenticateresult.fail("code was not found."); } //获取tokens var tokens = await exchangecodeasync(code, buildredirecturi(options.callbackpath)); var identity = new claimsidentity(options.claimsissuer); authenticationticket ticket = null; if (options.wechatscope == options.infoscope) { //获取用户信息 ticket = await createticketasync(identity, properties, tokens); } else { //不获取信息,只使用openid identity.addclaim(new claim(claimtypes.nameidentifier, tokens.tokentype, claimvaluetypes.string, options.claimsissuer)); ticket = new authenticationticket(new claimsprincipal(identity), properties, options.authenticationscheme); } if (ticket != null) { return authenticateresult.success(ticket); } else { return authenticateresult.fail("failed to retrieve user information from remote server."); } } /// <summary> /// oauth第一步,获取code /// </summary> /// <param name="properties"></param> /// <param name="redirecturi"></param> /// <returns></returns> protected override string buildchallengeurl(authenticationproperties properties, string redirecturi) { //加密oauth状态 var oauthstate = options.statedataformat.protect(properties); // redirecturi = $"{redirecturi}?{nameof(oauthstate)}={oauthstate}"; var querybuilder = new querybuilder() { { "appid", options.clientid }, { "redirect_uri", redirecturi }, { "response_type", "code" }, { "scope", options.wechatscope }, { "state", options.stateaddition }, }; return options.authorizationendpoint + querybuilder.tostring(); } /// <summary> /// oauth第二步,获取token /// </summary> /// <param name="code"></param> /// <param name="redirecturi"></param> /// <returns></returns> protected override async task<oauthtokenresponse> exchangecodeasync(string code, string redirecturi) { var tokenrequestparameters = new dictionary<string, string>() { { "appid", options.clientid }, { "secret", options.clientsecret }, { "code", code }, { "grant_type", "authorization_code" }, }; var requestcontent = new formurlencodedcontent(tokenrequestparameters); var requestmessage = new httprequestmessage(httpmethod.post, options.tokenendpoint); requestmessage.headers.accept.add(new mediatypewithqualityheadervalue("application/json")); requestmessage.content = requestcontent; var response = await backchannel.sendasync(requestmessage, context.requestaborted); if (response.issuccessstatuscode) { var payload = jobject.parse(await response.content.readasstringasync()); string errcode = payload.value<string>("errcode"); string errmsg = payload.value<string>("errmsg"); if (!string.isnullorempty(errcode) | !string.isnullorempty(errmsg)) { return oauthtokenresponse.failed(new exception($"errcode:{errcode},errmsg:{errmsg}")); } var tokens = oauthtokenresponse.success(payload); //借用tokentype属性保存openid tokens.tokentype = payload.value<string>("openid"); return tokens; } else { var error = "oauth token endpoint failure"; return oauthtokenresponse.failed(new exception(error)); } } /// <summary> /// oauth第四步,获取用户信息 /// </summary> /// <param name="identity"></param> /// <param name="properties"></param> /// <param name="tokens"></param> /// <returns></returns> protected override async task<authenticationticket> createticketasync(claimsidentity identity, authenticationproperties properties, oauthtokenresponse tokens) { var querybuilder = new querybuilder() { { "access_token", tokens.accesstoken }, { "openid", tokens.tokentype },//在第二步中,openid被存入tokentype属性 { "lang", "zh_cn" } }; var inforequest = options.userinformationendpoint + querybuilder.tostring(); var response = await backchannel.getasync(inforequest, context.requestaborted); if (!response.issuccessstatuscode) { throw new httprequestexception($"failed to retrieve wechat user information ({response.statuscode}) please check if the authentication information is correct and the corresponding wechat graph api is enabled."); } var user = jobject.parse(await response.content.readasstringasync()); var ticket = new authenticationticket(new claimsprincipal(identity), properties, options.authenticationscheme); var context = new oauthcreatingticketcontext(ticket, context, options, backchannel, tokens, user); var identifier = user.value<string>("openid"); if (!string.isnullorempty(identifier)) { identity.addclaim(new claim(claimtypes.nameidentifier, identifier, claimvaluetypes.string, options.claimsissuer)); } var nickname = user.value<string>("nickname"); if (!string.isnullorempty(nickname)) { identity.addclaim(new claim(claimtypes.name, nickname, claimvaluetypes.string, options.claimsissuer)); } var sex = user.value<string>("sex"); if (!string.isnullorempty(sex)) { identity.addclaim(new claim("urn:wechat:sex", sex, claimvaluetypes.string, options.claimsissuer)); } var country = user.value<string>("country"); if (!string.isnullorempty(country)) { identity.addclaim(new claim(claimtypes.country, country, claimvaluetypes.string, options.claimsissuer)); } var province = user.value<string>("province"); if (!string.isnullorempty(province)) { identity.addclaim(new claim(claimtypes.stateorprovince, province, claimvaluetypes.string, options.claimsissuer)); } var city = user.value<string>("city"); if (!string.isnullorempty(city)) { identity.addclaim(new claim("urn:wechat:city", city, claimvaluetypes.string, options.claimsissuer)); } var headimgurl = user.value<string>("headimgurl"); if (!string.isnullorempty(headimgurl)) { identity.addclaim(new claim("urn:wechat:headimgurl", headimgurl, claimvaluetypes.string, options.claimsissuer)); } var unionid = user.value<string>("unionid"); if (!string.isnullorempty(unionid)) { identity.addclaim(new claim("urn:wechat:unionid", unionid, claimvaluetypes.string, options.claimsissuer)); } await options.events.creatingticket(context); return context.ticket; } } }
wechatmiddleware.cs
// copyright (c) .net foundation. all rights reserved. // licensed under the apache license, version 2.0. see license.txt in the project root for license information. using system; using system.globalization; using system.text.encodings.web; using microsoft.aspnetcore.authentication.oauth; using microsoft.aspnetcore.builder; using microsoft.aspnetcore.dataprotection; using microsoft.aspnetcore.http; using microsoft.extensions.logging; using microsoft.extensions.options; namespace microsoft.aspnetcore.authentication.wechat { /// <summary> /// an asp.net core middleware for authenticating users using wechat. /// </summary> public class wechatmiddleware : oauthmiddleware<wechatoptions> { /// <summary> /// initializes a new <see cref="wechatmiddleware"/>. /// </summary> /// <param name="next">the next middleware in the http pipeline to invoke.</param> /// <param name="dataprotectionprovider"></param> /// <param name="loggerfactory"></param> /// <param name="encoder"></param> /// <param name="sharedoptions"></param> /// <param name="options">configuration options for the middleware.</param> public wechatmiddleware( requestdelegate next, idataprotectionprovider dataprotectionprovider, iloggerfactory loggerfactory, urlencoder encoder, ioptions<sharedauthenticationoptions> sharedoptions, ioptions<wechatoptions> options) : base(next, dataprotectionprovider, loggerfactory, encoder, sharedoptions, options) { if (next == null) { throw new argumentnullexception(nameof(next)); } if (dataprotectionprovider == null) { throw new argumentnullexception(nameof(dataprotectionprovider)); } if (loggerfactory == null) { throw new argumentnullexception(nameof(loggerfactory)); } if (encoder == null) { throw new argumentnullexception(nameof(encoder)); } if (sharedoptions == null) { throw new argumentnullexception(nameof(sharedoptions)); } if (options == null) { throw new argumentnullexception(nameof(options)); } if (string.isnullorempty(options.appid)) { throw new argumentexception(string.format(cultureinfo.currentculture, nameof(options.appid))); } if (string.isnullorempty(options.appsecret)) { throw new argumentexception(string.format(cultureinfo.currentculture, nameof(options.appsecret))); } } /// <summary> /// provides the <see cref="authenticationhandler{t}"/> object for processing authentication-related requests. /// </summary> /// <returns>an <see cref="authenticationhandler{t}"/> configured with the <see cref="wechatoptions"/> supplied to the constructor.</returns> protected override authenticationhandler<wechatoptions> createhandler() { return new wechathandler(backchannel); } } }
wechatoptions.cs
// copyright (c) .net foundation. all rights reserved. // licensed under the apache license, version 2.0. see license.txt in the project root for license information. using system.collections.generic; using microsoft.aspnetcore.authentication.wechat; using microsoft.aspnetcore.http; using microsoft.aspnetcore.identity; namespace microsoft.aspnetcore.builder { /// <summary> /// configuration options for <see cref="wechatmiddleware"/>. /// </summary> public class wechatoptions : oauthoptions { /// <summary> /// initializes a new <see cref="wechatoptions"/>. /// </summary> public wechatoptions() { authenticationscheme = wechatdefaults.authenticationscheme; displayname = authenticationscheme; callbackpath = new pathstring("/signin-wechat"); stateaddition = "#wechat_redirect"; authorizationendpoint = wechatdefaults.authorizationendpoint; tokenendpoint = wechatdefaults.tokenendpoint; userinformationendpoint = wechatdefaults.userinformationendpoint; //savetokens = true; //basescope (不弹出授权页面,直接跳转,只能获取用户openid), //infoscope (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息) wechatscope = infoscope; } // wechat uses a non-standard term for this field. /// <summary> /// gets or sets the wechat-assigned appid. /// </summary> public string appid { get { return clientid; } set { clientid = value; } } // wechat uses a non-standard term for this field. /// <summary> /// gets or sets the wechat-assigned app secret. /// </summary> public string appsecret { get { return clientsecret; } set { clientsecret = value; } } public string stateaddition { get; set; } public string wechatscope { get; set; } public string basescope = "snsapi_base"; public string infoscope = "snsapi_userinfo"; } }
本文已被整理到了《asp.net微信开发教程汇总》,欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Net Core Web Api项目与在NginX下发布的方法
asp.net core3.1 引用的元包dll版本兼容性问题解决方案
IdentityServer4实现.Net Core API接口权限认证(快速入门)
ASP.NET Core MVC通过IViewLocationExpander扩展视图搜索路径的实现
网友评论