這篇文章主要介紹了ASP.NET Core集成微信登錄的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
工具:
Visual Studio 2015 update 3
Asp.Net Core 1.0
1 準(zhǔn)備工作
申請(qǐng)微信公眾平臺(tái)接口測(cè)試帳號(hào),申請(qǐng)網(wǎng)址:(mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login)。申請(qǐng)接口測(cè)試號(hào)無(wú)需公眾帳號(hào),可以直接體驗(yàn)和測(cè)試公眾平臺(tái)所有高級(jí)接口。
1.1 配置接口信息
1.2 修改網(wǎng)頁(yè)授權(quán)信息
點(diǎn)擊“修改”后在彈出頁(yè)面填入你的網(wǎng)站域名:
2 新建網(wǎng)站項(xiàng)目
2.1 選擇ASP.NET Core Web Application 模板
2.2 選擇Web 應(yīng)用程序,并更改身份驗(yàn)證為個(gè)人用戶賬戶
3 集成微信登錄功能
3.1添加引用
打開(kāi)project.json文件,添加引用Microsoft.AspNetCore.Authentication.OAuth
3.2 添加代碼文件
在項(xiàng)目中新建文件夾,命名為WeChatOAuth,并添加代碼文件(本文最后附全部代碼)。
3.3 注冊(cè)微信登錄中間件
打開(kāi)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狀態(tài) 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 (不彈出授權(quán)頁(yè)面,直接跳轉(zhuǎn),只能獲取用戶openid), //InfoScope (彈出授權(quán)頁(yè)面,可通過(guò)openid拿到昵稱、性別、所在地。并且,即使在未關(guān)注的情況下,只要用戶授權(quán),也能獲取其信息) 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 Core集成微信登錄的實(shí)例圖解的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機(jī)

Video Face Swap
使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)代碼編輯軟件(SublimeText3)

抖音網(wǎng)頁(yè)版的登錄入口是https://www.douyin.com/。登錄步驟包括:1.打開(kāi)瀏覽器;2.輸入網(wǎng)址https://www.douyin.com/;3.點(diǎn)擊“登錄”按鈕并選擇登錄方式;4.輸入賬號(hào)密碼;5.完成登錄。網(wǎng)頁(yè)版提供了瀏覽、搜索、互動(dòng)、上傳視頻和個(gè)人主頁(yè)管理等功能,具有大屏幕體驗(yàn)、多任務(wù)處理、便捷的賬號(hào)管理和數(shù)據(jù)統(tǒng)計(jì)等優(yōu)勢(shì)。

拷貝漫畫無(wú)疑是一個(gè)不容錯(cuò)過(guò)的寶藏。在這里,你可以找到各種風(fēng)格的籃球漫畫,從熱血?jiǎng)?lì)志的競(jìng)技故事,到輕松幽默的日常喜劇,應(yīng)有盡有。無(wú)論是想重溫經(jīng)典,還是想發(fā)掘新作,拷貝漫畫都能滿足你的需求。通過(guò)拷貝漫畫提供的正版在線閱讀入口,你將告別盜版資源的困擾,享受高清流暢的閱讀體驗(yàn),更能支持你喜愛(ài)的漫畫作者,為正版漫畫的發(fā)展貢獻(xiàn)一份力量。

選擇UC瀏覽器還是QQ瀏覽器取決于你的需求:1.UC瀏覽器適合追求快速加載和豐富娛樂(lè)功能的用戶;2.QQ瀏覽器適合需要穩(wěn)定性和與騰訊產(chǎn)品無(wú)縫連接的用戶。

結(jié)合 2025 年最新行業(yè)動(dòng)態(tài)與多維度評(píng)測(cè)數(shù)據(jù),以下為綜合排名前十的 AI 寫作軟件推薦,涵蓋通用創(chuàng)作、學(xué)術(shù)研究、商業(yè)營(yíng)銷等主流場(chǎng)景,同時(shí)兼顧中文優(yōu)化與本地化服務(wù):

奈斯漫畫,一個(gè)致力于為漫畫愛(ài)好者打造的沉浸式閱讀體驗(yàn)平臺(tái),匯聚了海量國(guó)內(nèi)外優(yōu)質(zhì)漫畫資源。它不僅僅是一個(gè)漫畫閱讀平臺(tái),更是一個(gè)連接漫畫家與讀者、分享漫畫文化的社區(qū)。通過(guò)簡(jiǎn)潔直觀的界面設(shè)計(jì)和強(qiáng)大的搜索功能,奈斯漫畫讓你能夠輕松找到心儀的作品,享受流暢舒適的閱讀體驗(yàn)。告別漫長(zhǎng)的等待和繁瑣的操作,即刻進(jìn)入奈斯漫畫的世界,開(kāi)啟你的漫畫之旅吧!

蛙漫漫畫,憑借其豐富多元的漫畫資源和便捷流暢的在線閱讀體驗(yàn),已成為眾多漫畫愛(ài)好者的首選。它就像一個(gè)充滿活力的池塘,源源不斷地涌現(xiàn)出新鮮有趣的故事,等待著你去發(fā)現(xiàn)和探索。蛙漫漫畫涵蓋了各種題材,從熱血冒險(xiǎn)到甜蜜戀愛(ài),從奇幻科幻到懸疑推理,無(wú)論你喜歡哪種類型,都能在這里找到心儀的作品。其簡(jiǎn)潔直觀的界面設(shè)計(jì),更讓你能夠輕松上手,快速找到想看的漫畫,沉浸在精彩紛呈的漫畫世界中。

在這里,您可以盡情暢游于浩瀚的漫畫海洋,探索各種題材和風(fēng)格的作品,從熱血激昂的少年漫,到細(xì)膩動(dòng)人的少女漫,從懸疑燒腦的推理漫,到輕松搞笑的日常漫,應(yīng)有盡有,總有一款能夠觸動(dòng)您的心弦。我們不僅擁有海量的正版漫畫資源,還不斷引進(jìn)和更新最新的作品,確保您能夠第一時(shí)間閱讀到您喜愛(ài)的漫畫。

2025b安最新官網(wǎng)入口地址:https://www.marketwebb.co/zh-CN/join?ref=507720986&type=wenzi;幣安(Binance)交易所是一家全球性的加密貨幣交易所,服務(wù)包括北美、歐洲、臺(tái)灣、中東、香港、馬來(lái)西亞在內(nèi)的180個(gè)國(guó)家地區(qū),提供超過(guò)600種加密貨幣,在全球擁有2.7億注冊(cè)用戶。
