From fb46e21c474eb35af51da685cee923f39684a80c Mon Sep 17 00:00:00 2001 From: Loongle Date: Fri, 21 Mar 2025 19:13:19 +0800 Subject: [PATCH 01/10] Add Bilibili provider --- AspNet.Security.OAuth.Providers.sln | 7 + README.md | 2 + .../AspNet.Security.OAuth.Bilibili.csproj | 18 ++ .../BilibiliAuthenticationConstants.cs | 18 ++ .../BilibiliAuthenticationDefaults.cs | 48 ++++ .../BilibiliAuthenticationExtensions.cs | 74 ++++++ .../BilibiliAuthenticationHandler.cs | 218 ++++++++++++++++++ .../BilibiliAuthenticationOptions.cs | 30 +++ .../Bilibili/BilibiliTests.cs | 61 +++++ .../Bilibili/bundle.json | 46 ++++ 10 files changed, 522 insertions(+) create mode 100644 src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj create mode 100644 src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationConstants.cs create mode 100644 src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationDefaults.cs create mode 100644 src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationExtensions.cs create mode 100644 src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs create mode 100644 src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationOptions.cs create mode 100644 test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs create mode 100644 test/AspNet.Security.OAuth.Providers.Tests/Bilibili/bundle.json diff --git a/AspNet.Security.OAuth.Providers.sln b/AspNet.Security.OAuth.Providers.sln index b9ec15bed..3be56d15d 100644 --- a/AspNet.Security.OAuth.Providers.sln +++ b/AspNet.Security.OAuth.Providers.sln @@ -318,6 +318,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.Security.OAuth.GitCo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.Security.OAuth.Atlassian", "src\AspNet.Security.OAuth.Atlassian\AspNet.Security.OAuth.Atlassian.csproj", "{D2110C1B-6FE1-4D9A-81ED-93FB2AC85049}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.Security.OAuth.Bilibili", "src\AspNet.Security.OAuth.Bilibili\AspNet.Security.OAuth.Bilibili.csproj", "{8350C405-9E17-4110-B9A8-0AB43A8816B7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -740,6 +742,10 @@ Global {D2110C1B-6FE1-4D9A-81ED-93FB2AC85049}.Debug|Any CPU.Build.0 = Debug|Any CPU {D2110C1B-6FE1-4D9A-81ED-93FB2AC85049}.Release|Any CPU.ActiveCfg = Release|Any CPU {D2110C1B-6FE1-4D9A-81ED-93FB2AC85049}.Release|Any CPU.Build.0 = Release|Any CPU + {8350C405-9E17-4110-B9A8-0AB43A8816B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8350C405-9E17-4110-B9A8-0AB43A8816B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8350C405-9E17-4110-B9A8-0AB43A8816B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8350C405-9E17-4110-B9A8-0AB43A8816B7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -855,6 +861,7 @@ Global {F3E62C24-5F82-4CF5-A994-0E10D04FB495} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D} {668833D5-DB6A-475F-B0FD-A03462B037B8} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D} {D2110C1B-6FE1-4D9A-81ED-93FB2AC85049} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D} + {8350C405-9E17-4110-B9A8-0AB43A8816B7} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C7B54DE2-6407-4802-AD9C-CE54BF414C8C} diff --git a/README.md b/README.md index d0cf81be2..bd87dc99c 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ We would love it if you could help contributing to this repository. * [Vicente Yu](https://github.com/vicenteyu) * [Volodymyr Baydalka](https://github.com/zVolodymyr) * [Logan Dam](https://github.com/biltongza) +* [Loongle Tse](https://github.com/loongle) ## Security policy @@ -167,6 +168,7 @@ If a provider you're looking for does not exist, consider making a PR to add one | Baidu | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Baidu?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Baidu/ "Download AspNet.Security.OAuth.Baidu from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Baidu?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Baidu "Download AspNet.Security.OAuth.Baidu from MyGet.org") | [Documentation](https://developer.baidu.com/ "Baidu developer documentation") | | Basecamp | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Basecamp?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Basecamp/ "Download AspNet.Security.OAuth.Basecamp from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Basecamp?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Basecamp "Download AspNet.Security.OAuth.Basecamp from MyGet.org") | [Documentation](https://github.com/basecamp/api/blob/master/sections/authentication.md "Basecamp developer documentation") | | BattleNet | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.BattleNet?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.BattleNet/ "Download AspNet.Security.OAuth.BattleNet from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.BattleNet?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.BattleNet "Download AspNet.Security.OAuth.BattleNet from MyGet.org") | [Documentation](https://develop.battle.net/documentation/guides/using-oauth "BattleNet developer documentation") | +| Bilibili | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Bilibili?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Bilibili/ "Download AspNet.Security.OAuth.Bilibili from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Bilibili?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Bilibili "Download AspNet.Security.OAuth.Bilibili from MyGet.org") | [Documentation](https://openhome.bilibili.com/doc/4/aac73b2e-4ff2-b75c-4c96-35ced865797b#h1-- "Bilibili developer documentation") | | Bitbucket | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Bitbucket?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Bitbucket/ "Download AspNet.Security.OAuth.Bitbucket from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Bitbucket?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Bitbucket "Download AspNet.Security.OAuth.Bitbucket from MyGet.org") | [Documentation](https://developer.atlassian.com/bitbucket/api/2/reference/meta/authentication "Bitbucket developer documentation") | | Buffer | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Buffer?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Buffer/ "Download AspNet.Security.OAuth.Buffer from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Buffer?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Buffer "Download AspNet.Security.OAuth.Buffer from MyGet.org") | [Documentation](https://buffer.com/developers/api/oauth "Buffer developer documentation") | | Calendly | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Calendly?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Calendly/ "Download AspNet.Security.OAuth.Calendly from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Calendly?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Calendly "Download AspNet.Security.OAuth.Calendly from MyGet.org") | [Documentation](https://developer.calendly.com/api-docs/3cefb59b832eb-calendly-o-auth-2-0 "Calendly developer documentation") | diff --git a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj new file mode 100644 index 000000000..72c40aa14 --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj @@ -0,0 +1,18 @@ + + + + $(DefaultNetCoreTargetFramework) + + + + ASP.NET Core security middleware enabling Bilibili authentication. + Loongle Tse + bilibili;aspnetcore;authentication;oauth;security + + + + + + + + diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationConstants.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationConstants.cs new file mode 100644 index 000000000..9567fb132 --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationConstants.cs @@ -0,0 +1,18 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +namespace AspNet.Security.OAuth.Bilibili; + +/// +/// Contains constants specific to the . +/// +public static class BilibiliAuthenticationConstants +{ + public static class Claims + { + public const string Face = "urn:bilibili:face"; + } +} diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationDefaults.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationDefaults.cs new file mode 100644 index 000000000..da6f6c17d --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationDefaults.cs @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +namespace AspNet.Security.OAuth.Bilibili; + +/// +/// Default values for Bilibili authentication. +/// +public static class BilibiliAuthenticationDefaults +{ + /// + /// Default value for . + /// + public const string AuthenticationScheme = "Bilibili"; + + /// + /// Default value for . + /// + public static readonly string DisplayName = "Bilibili"; + + /// + /// Default value for . + /// + public static readonly string CallbackPath = "/signin-bilibili"; + + /// + /// Default value for . + /// + public static readonly string Issuer = "Bilibili"; + + /// + /// Default value for . + /// + public static readonly string AuthorizationEndpoint = "https://account.bilibili.com/pc/account-pc/auth/oauth"; + + /// + /// Default value for . + /// + public static readonly string TokenEndpoint = "https://api.bilibili.com/x/account-oauth2/v1/token"; + + /// + /// Default value for . + /// + public static readonly string UserInformationEndpoint = "https://member.bilibili.com/arcopen/fn/user/account/info"; +} diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationExtensions.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationExtensions.cs new file mode 100644 index 000000000..74937f9ad --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationExtensions.cs @@ -0,0 +1,74 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +using AspNet.Security.OAuth.Bilibili; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extension methods to add Bilibili authentication capabilities to an HTTP application pipeline. +/// +public static class BilibiliAuthenticationExtensions +{ + /// + /// Adds to the specified + /// , which enables Bilibili authentication capabilities. + /// + /// The authentication builder. + /// A reference to this instance after the operation has completed. + public static AuthenticationBuilder AddBilibili([NotNull] this AuthenticationBuilder builder) + { + return builder.AddBilibili(BilibiliAuthenticationDefaults.AuthenticationScheme, options => { }); + } + + /// + /// Adds to the specified + /// , which enables Bilibili authentication capabilities. + /// + /// The authentication builder. + /// The delegate used to configure the OpenID 2.0 options. + /// A reference to this instance after the operation has completed. + public static AuthenticationBuilder AddBilibili( + [NotNull] this AuthenticationBuilder builder, + [NotNull] Action configuration) + { + return builder.AddBilibili(BilibiliAuthenticationDefaults.AuthenticationScheme, configuration); + } + + /// + /// Adds to the specified + /// , which enables Bilibili authentication capabilities. + /// + /// The authentication builder. + /// The authentication scheme associated with this instance. + /// The delegate used to configure the Bilibili options. + /// The . + public static AuthenticationBuilder AddBilibili( + [NotNull] this AuthenticationBuilder builder, + [NotNull] string scheme, + [NotNull] Action configuration) + { + return builder.AddBilibili(scheme, BilibiliAuthenticationDefaults.DisplayName, configuration); + } + + /// + /// Adds to the specified + /// , which enables Bilibili authentication capabilities. + /// + /// The authentication builder. + /// The authentication scheme associated with this instance. + /// The optional display name associated with this instance. + /// The delegate used to configure the Bilibili options. + /// The . + public static AuthenticationBuilder AddBilibili( + [NotNull] this AuthenticationBuilder builder, + [NotNull] string scheme, + [CanBeNull] string caption, + [NotNull] Action configuration) + { + return builder.AddOAuth(scheme, caption, configuration); + } +} diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs new file mode 100644 index 000000000..92f48c7a6 --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -0,0 +1,218 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +using System.Globalization; +using System.Net; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace AspNet.Security.OAuth.Bilibili; + +public partial class BilibiliAuthenticationHandler : OAuthHandler +{ + public BilibiliAuthenticationHandler( + [NotNull] IOptionsMonitor options, + [NotNull] ILoggerFactory logger, + [NotNull] UrlEncoder encoder) + : base(options, logger, encoder) + { + } + + protected override string BuildChallengeUrl([NotNull] AuthenticationProperties properties, [NotNull] string redirectUri) + { + var parameters = new Dictionary + { + ["client_id"] = Options.ClientId, // Used instead of "client_id" + ["response_type"] = "code", + ["gourl"] = redirectUri + }; + + foreach (var additionalParameter in Options.AdditionalAuthorizationParameters) + { + parameters.Add(additionalParameter.Key, additionalParameter.Value); + } + + parameters["state"] = Options.StateDataFormat.Protect(properties); + + return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters); + } + + protected override async Task ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context) + { + // See https://open.bilibili.com/doc/4/eaf0e2b5-bde9-b9a0-9be1-019bb455701c#h1-u7B80u4ECB for details. + var tokenRequestParameters = new Dictionary() + { + ["client_id"] = Options.ClientId, + ["code"] = context.Code, + ["client_secret"] = Options.ClientSecret, + ["grant_type"] = "authorization_code", + }; + + using var tokenRequestContent = new FormUrlEncodedContent(tokenRequestParameters); + + using var response = await Backchannel.PostAsync(Options.TokenEndpoint, tokenRequestContent, Context.RequestAborted); + + if (!response.IsSuccessStatusCode) + { + await Log.AccessTokenError(Logger, response, Context.RequestAborted); + return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token.")); + } + + using var stream = await response.Content.ReadAsStreamAsync(Context.RequestAborted); + using var document = await JsonDocument.ParseAsync(stream); + + var mainElement = document.RootElement; + if (!ValidateReturnCode(mainElement, out var code)) + { + return OAuthTokenResponse.Failed(new Exception($"An error (Code:{code}) occurred while retrieving an access token.")); + } + + var payload = JsonDocument.Parse(mainElement.GetProperty("data").GetRawText()); + return OAuthTokenResponse.Success(payload); + } + + private static string ComputeHmacSHA256(string key, string data) + { + using var hmacsha256 = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(key)); + var hash = hmacsha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data)); + return Convert.ToHexStringLower(hash); + } + +#pragma warning disable CA5351 + private static string ComputeMd5(string input) + { + var inputBytes = Encoding.ASCII.GetBytes(input); + var hashBytes = System.Security.Cryptography.MD5.HashData(inputBytes); + return Convert.ToHexStringLower(hashBytes).Replace("-", string.Empty, StringComparison.OrdinalIgnoreCase).ToLower(CultureInfo.InvariantCulture); + } +#pragma warning disable CA5351 + + private static string BuildSignatureString(HttpRequestMessage request, string appSecret) + { + var headers = request.Headers + .Where(h => h.Key.StartsWith("x-bili-", StringComparison.OrdinalIgnoreCase)) + .OrderBy(h => h.Key) + .Select(h => $"{h.Key}:{string.Join(",", h.Value)}") + .ToList(); + + var signatureString = string.Join("\n", headers); + var signature = ComputeHmacSHA256(appSecret, signatureString); + + return signature; + } + + protected override async Task CreateTicketAsync( + [NotNull] ClaimsIdentity identity, + [NotNull] AuthenticationProperties properties, + [NotNull] OAuthTokenResponse tokens) + { + using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); + request.Headers.Add("Access-Token", tokens.AccessToken); + request.Headers.Add("x-bili-accesskeyid", Options.ClientId); + request.Headers.Add("x-bili-content-md5", ComputeMd5(string.Empty)); + request.Headers.Add("x-bili-signature-method", "HMAC-SHA256"); + request.Headers.Add("x-bili-signature-nonce", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("x-bili-signature-version", "2.0"); + request.Headers.Add("x-bili-timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("Host", "member.bilibili.com"); + request.Headers.Add("Connection", "keep-alive"); + + var signature = BuildSignatureString(request, Options.ClientSecret); + request.Headers.Add("Authorization", signature); + + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + using var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted); + if (!response.IsSuccessStatusCode) + { + await Log.UserProfileErrorAsync(Logger, response, Context.RequestAborted); + throw new HttpRequestException("An error occurred while retrieving the user profile."); + } + + using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync(Context.RequestAborted)); + + var mainElement = payload.RootElement; + if (!ValidateReturnCode(mainElement, out var code)) + { + throw new AuthenticationFailureException($"An error (ErrorCode:{code}) occurred while retrieving user information."); + } + + var principal = new ClaimsPrincipal(identity); + var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, mainElement.GetProperty("data")); + context.RunClaimActions(); + + await Events.CreatingTicket(context); + return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name); + } + + /// + /// Check the code sent back by server for potential server errors. + /// + /// Main part of json document from response + /// Returned error_code from server + /// See https://open.bilibili.com/doc/4/8673959e-f7bb-56e6-6e68-d225f971b81b#h1-u63A5u53E3u7B7Eu540Du5B9Eu73B0u6807u51C6u548Cu72B6u6001u7801 for details. + /// True if succeed, otherwise false. + private static bool ValidateReturnCode(JsonElement element, out int code) + { + code = 0; + if (!element.TryGetProperty("code", out JsonElement errorCodeElement)) + { + return true; + } + + code = errorCodeElement.GetInt32()!; + + return code == 0; + } + + private static partial class Log + { + internal static async Task UserProfileErrorAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken) + { + UserProfileError( + logger, + response.StatusCode, + response.Headers.ToString(), + await response.Content.ReadAsStringAsync(cancellationToken)); + } + + internal static async Task AccessTokenError(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken) + { + AccessTokenError( + logger, + response.StatusCode, + response.Headers.ToString(), + await response.Content.ReadAsStringAsync(cancellationToken)); + } + + [LoggerMessage(1, LogLevel.Error, "An error occurred while retrieving the user profile: the remote server returned a {Status} response with the following payload: {Headers} {Body}.")] + private static partial void UserProfileError( + ILogger logger, + HttpStatusCode status, + string headers, + string body); + + [LoggerMessage(2, LogLevel.Error, "An error occurred while retrieving an access token: the remote server returned a {Status} response with the following payload: {Headers} {Body}.")] + private static partial void AccessTokenError( + ILogger logger, + HttpStatusCode status, + string headers, + string body); + + [LoggerMessage(2, LogLevel.Warning, "An error occurred while retrieving the email address associated with the logged in user: the remote server returned a {Status} response with the following payload: {Headers} {Body}.")] + private static partial void EmailAddressError( + ILogger logger, + HttpStatusCode status, + string headers, + string body); + } +} diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationOptions.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationOptions.cs new file mode 100644 index 000000000..bbbc44943 --- /dev/null +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationOptions.cs @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +using System.Security.Claims; +using static AspNet.Security.OAuth.Bilibili.BilibiliAuthenticationConstants; + +namespace AspNet.Security.OAuth.Bilibili; + +/// +/// Defines a set of options used by . +/// +public class BilibiliAuthenticationOptions : OAuthOptions +{ + public BilibiliAuthenticationOptions() + { + ClaimsIssuer = BilibiliAuthenticationDefaults.Issuer; + CallbackPath = BilibiliAuthenticationDefaults.CallbackPath; + + AuthorizationEndpoint = BilibiliAuthenticationDefaults.AuthorizationEndpoint; + TokenEndpoint = BilibiliAuthenticationDefaults.TokenEndpoint; + UserInformationEndpoint = BilibiliAuthenticationDefaults.UserInformationEndpoint; + + ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "openid"); + ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); + ClaimActions.MapJsonKey(Claims.Face, "face"); + } +} diff --git a/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs new file mode 100644 index 000000000..9445296bc --- /dev/null +++ b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs @@ -0,0 +1,61 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers + * for more information concerning the license and the contributors participating to this project. + */ + +using System.Web; +using Microsoft.AspNetCore.WebUtilities; + +namespace AspNet.Security.OAuth.Bilibili; + +public class BilibiliTests(ITestOutputHelper outputHelper) : OAuthTests(outputHelper) +{ + public override string DefaultScheme => BilibiliAuthenticationDefaults.AuthenticationScheme; + + protected internal override void RegisterAuthentication(AuthenticationBuilder builder) + { + builder.AddBilibili(options => + { + ConfigureDefaults(builder, options); + options.ClientSecret = "ee9ee51ee0ceabdeeeb9459168eeeef7"; + }); + LoopbackRedirectHandler.RedirectUri = "http://localhost/signin-bilibili"; + } + + [Theory] + [InlineData(ClaimTypes.NameIdentifier, "9844422354fe42629cd126**********")] + [InlineData("urn:bilibili:face", "https://i0.hdslb.com/bfs/face/member/noface.jpg")] + [InlineData(ClaimTypes.Name, "TestAccount")] + public async Task Can_Sign_In_Using_Bilibili(string claimType, string claimValue) + => await AuthenticateUserAndAssertClaimValue(claimType, claimValue); + + [Fact] + public async Task BuildChallengeUrl_Generates_Correct_Url() + { + // Arrange + var options = new BilibiliAuthenticationOptions(); + + var redirectUrl = "https://my-site.local/signin-bilibili"; + + // Act + Uri actual = await BuildChallengeUriAsync( + options, + redirectUrl, + (options, loggerFactory, encoder) => new BilibiliAuthenticationHandler(options, loggerFactory, encoder)); + + // Assert + actual.ShouldNotBeNull(); + actual.ToString().ShouldStartWith("https://account.bilibili.com/pc/account-pc/auth/oauth"); + + var query = QueryHelpers.ParseQuery(actual.Query); + + query.ShouldContainKey("state"); + query.ShouldContainKeyAndValue("client_id", options.ClientId); + query.ShouldContainKeyAndValue("gourl", redirectUrl); + query.ShouldContainKeyAndValue("response_type", "code"); + + query.ShouldNotContainKey(OAuthConstants.CodeChallengeKey); + query.ShouldNotContainKey(OAuthConstants.CodeChallengeMethodKey); + } +} diff --git a/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/bundle.json b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/bundle.json new file mode 100644 index 000000000..6a451ac61 --- /dev/null +++ b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/bundle.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://raw.githubusercontent.com/justeat/httpclient-interception/master/src/HttpClientInterception/Bundles/http-request-bundle-schema.json", + "items": [ + { + "uri": "https://account.bilibili.com/pc/account-pc/auth/oauth", + "contentFormat": "json", + "contentJson": { + "code": "code", + "access_token": "secret-access-token", + "client_token": "client_token", + "refresh_token": "secret-refresh-token" + } + }, + { + "uri": "https://api.bilibili.com/x/account-oauth2/v1/token", + "contentFormat": "json", + "method": "POST", + "contentJson": { + "code": 0, + "message": "0", + "ttl": 1, + "data": { + "access_token": "1fbe4a8dc9624dfb84696b**********", + "expires_in": 1758100652, + "refresh_token": "e98d2aae693f019b6a4b2**********", + "scopes": [ "USER_INFO" ] + } + } + }, + { + "uri": "https://member.bilibili.com/arcopen/fn/user/account/info", + "contentFormat": "json", + "contentJson": { + "code": 0, + "data": { + "face": "https://i0.hdslb.com/bfs/face/member/noface.jpg", + "name": "TestAccount", + "openid": "9844422354fe42629cd126**********" + }, + "message": "0", + "request_id": "592a21bcf354ef1d525863**********", + "ttl": 1 + } + } + ] +} From 88b1511883d011669427617f0ac6101db7eb4256 Mon Sep 17 00:00:00 2001 From: Loongle Date: Tue, 25 Mar 2025 09:55:25 +0800 Subject: [PATCH 02/10] Modify as suggested --- .../AspNet.Security.OAuth.Bilibili.csproj | 5 ++++- .../BilibiliAuthenticationHandler.cs | 20 ++++++++++--------- .../Bilibili/BilibiliTests.cs | 1 - 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj index 72c40aa14..84c038c4f 100644 --- a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj +++ b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj @@ -1,6 +1,9 @@  - + + 9.2.0 + + true $(DefaultNetCoreTargetFramework) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 92f48c7a6..99c40208e 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Http.Headers; using System.Security.Claims; +using System.Security.Cryptography; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; @@ -82,8 +83,9 @@ protected override async Task ExchangeCodeAsync([NotNull] OA private static string ComputeHmacSHA256(string key, string data) { - using var hmacsha256 = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(key)); - var hash = hmacsha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data)); + var keyBytes = Encoding.UTF8.GetBytes(key); + var dataBytes = Encoding.UTF8.GetBytes(data); + var hash = HMACSHA256.HashData(keyBytes, dataBytes); return Convert.ToHexStringLower(hash); } @@ -91,8 +93,8 @@ private static string ComputeHmacSHA256(string key, string data) private static string ComputeMd5(string input) { var inputBytes = Encoding.ASCII.GetBytes(input); - var hashBytes = System.Security.Cryptography.MD5.HashData(inputBytes); - return Convert.ToHexStringLower(hashBytes).Replace("-", string.Empty, StringComparison.OrdinalIgnoreCase).ToLower(CultureInfo.InvariantCulture); + var hashBytes = MD5.HashData(inputBytes); + return Convert.ToHexStringLower(hashBytes); } #pragma warning disable CA5351 @@ -104,10 +106,9 @@ private static string BuildSignatureString(HttpRequestMessage request, string ap .Select(h => $"{h.Key}:{string.Join(",", h.Value)}") .ToList(); - var signatureString = string.Join("\n", headers); - var signature = ComputeHmacSHA256(appSecret, signatureString); + var signature = string.Join("\n", headers); - return signature; + return ComputeHmacSHA256(appSecret, signature); } protected override async Task CreateTicketAsync( @@ -115,14 +116,15 @@ protected override async Task CreateTicketAsync( [NotNull] AuthenticationProperties properties, [NotNull] OAuthTokenResponse tokens) { + var utcNow = TimeProvider.GetUtcNow(); using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); request.Headers.Add("Access-Token", tokens.AccessToken); request.Headers.Add("x-bili-accesskeyid", Options.ClientId); request.Headers.Add("x-bili-content-md5", ComputeMd5(string.Empty)); request.Headers.Add("x-bili-signature-method", "HMAC-SHA256"); - request.Headers.Add("x-bili-signature-nonce", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("x-bili-signature-nonce", utcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); request.Headers.Add("x-bili-signature-version", "2.0"); - request.Headers.Add("x-bili-timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("x-bili-timestamp", utcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); request.Headers.Add("Host", "member.bilibili.com"); request.Headers.Add("Connection", "keep-alive"); diff --git a/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs index 9445296bc..333ef2c0b 100644 --- a/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs +++ b/test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs @@ -18,7 +18,6 @@ protected internal override void RegisterAuthentication(AuthenticationBuilder bu builder.AddBilibili(options => { ConfigureDefaults(builder, options); - options.ClientSecret = "ee9ee51ee0ceabdeeeb9459168eeeef7"; }); LoopbackRedirectHandler.RedirectUri = "http://localhost/signin-bilibili"; } From e60942b762070ad9cc0fde551139481d54bb7df1 Mon Sep 17 00:00:00 2001 From: Loongle Date: Wed, 26 Mar 2025 09:35:19 +0800 Subject: [PATCH 03/10] Modify as suggested --- .../AspNet.Security.OAuth.Bilibili.csproj | 1 - .../BilibiliAuthenticationHandler.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj index 84c038c4f..943715f8d 100644 --- a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj +++ b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj @@ -1,7 +1,6 @@  - 9.2.0 true $(DefaultNetCoreTargetFramework) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 99c40208e..74c1cf777 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -106,7 +106,7 @@ private static string BuildSignatureString(HttpRequestMessage request, string ap .Select(h => $"{h.Key}:{string.Join(",", h.Value)}") .ToList(); - var signature = string.Join("\n", headers); + var signature = string.Join('\n', headers); return ComputeHmacSHA256(appSecret, signature); } From 1290543a3fbf31d061d48b087479d8727d3775c0 Mon Sep 17 00:00:00 2001 From: Loongle Date: Wed, 26 Mar 2025 16:34:22 +0800 Subject: [PATCH 04/10] Add PackageValidationBaselineVersion --- .../AspNet.Security.OAuth.Bilibili.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj index 943715f8d..c2b71d42d 100644 --- a/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj +++ b/src/AspNet.Security.OAuth.Bilibili/AspNet.Security.OAuth.Bilibili.csproj @@ -1,6 +1,7 @@  - + + 9.3.0 true $(DefaultNetCoreTargetFramework) From 2fe445bf2f581f3a62aa262b34902b692f4ef7bf Mon Sep 17 00:00:00 2001 From: Loongle Date: Sun, 30 Mar 2025 21:23:02 +0800 Subject: [PATCH 05/10] Remove invalid code --- .../BilibiliAuthenticationHandler.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 74c1cf777..25c61ce85 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -89,15 +89,6 @@ private static string ComputeHmacSHA256(string key, string data) return Convert.ToHexStringLower(hash); } -#pragma warning disable CA5351 - private static string ComputeMd5(string input) - { - var inputBytes = Encoding.ASCII.GetBytes(input); - var hashBytes = MD5.HashData(inputBytes); - return Convert.ToHexStringLower(hashBytes); - } -#pragma warning disable CA5351 - private static string BuildSignatureString(HttpRequestMessage request, string appSecret) { var headers = request.Headers @@ -120,7 +111,7 @@ protected override async Task CreateTicketAsync( using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); request.Headers.Add("Access-Token", tokens.AccessToken); request.Headers.Add("x-bili-accesskeyid", Options.ClientId); - request.Headers.Add("x-bili-content-md5", ComputeMd5(string.Empty)); + request.Headers.Add("x-bili-content-md5", "d41d8cd98f00b204e9800998ecf8427e"); request.Headers.Add("x-bili-signature-method", "HMAC-SHA256"); request.Headers.Add("x-bili-signature-nonce", utcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); request.Headers.Add("x-bili-signature-version", "2.0"); @@ -171,7 +162,7 @@ private static bool ValidateReturnCode(JsonElement element, out int code) return true; } - code = errorCodeElement.GetInt32()!; + code = errorCodeElement.GetInt32(); return code == 0; } From 90e8a2a2a9874d9521feeb99b48451c2650a5123 Mon Sep 17 00:00:00 2001 From: Loongle Date: Sun, 30 Mar 2025 21:55:13 +0800 Subject: [PATCH 06/10] Fix 4003 error code --- .../BilibiliAuthenticationHandler.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 25c61ce85..23a0d9357 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -109,15 +109,13 @@ protected override async Task CreateTicketAsync( { var utcNow = TimeProvider.GetUtcNow(); using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); - request.Headers.Add("Access-Token", tokens.AccessToken); + request.Headers.Add("access-token", tokens.AccessToken); request.Headers.Add("x-bili-accesskeyid", Options.ClientId); request.Headers.Add("x-bili-content-md5", "d41d8cd98f00b204e9800998ecf8427e"); request.Headers.Add("x-bili-signature-method", "HMAC-SHA256"); request.Headers.Add("x-bili-signature-nonce", utcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); request.Headers.Add("x-bili-signature-version", "2.0"); request.Headers.Add("x-bili-timestamp", utcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); - request.Headers.Add("Host", "member.bilibili.com"); - request.Headers.Add("Connection", "keep-alive"); var signature = BuildSignatureString(request, Options.ClientSecret); request.Headers.Add("Authorization", signature); From 36ab363dd205082c2021a22bb4d7df6c53fd791d Mon Sep 17 00:00:00 2001 From: Loongle Date: Tue, 1 Apr 2025 10:01:02 +0800 Subject: [PATCH 07/10] Using real random noce --- .../BilibiliAuthenticationHandler.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 23a0d9357..06ccfce6f 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -4,6 +4,7 @@ * for more information concerning the license and the contributors participating to this project. */ +using System.Buffers.Text; using System.Globalization; using System.Net; using System.Net.Http.Headers; @@ -106,16 +107,15 @@ protected override async Task CreateTicketAsync( [NotNull] ClaimsIdentity identity, [NotNull] AuthenticationProperties properties, [NotNull] OAuthTokenResponse tokens) - { - var utcNow = TimeProvider.GetUtcNow(); + { using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); request.Headers.Add("access-token", tokens.AccessToken); request.Headers.Add("x-bili-accesskeyid", Options.ClientId); request.Headers.Add("x-bili-content-md5", "d41d8cd98f00b204e9800998ecf8427e"); request.Headers.Add("x-bili-signature-method", "HMAC-SHA256"); - request.Headers.Add("x-bili-signature-nonce", utcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("x-bili-signature-nonce", Base64Url.EncodeToString(RandomNumberGenerator.GetBytes(256 / 8))); request.Headers.Add("x-bili-signature-version", "2.0"); - request.Headers.Add("x-bili-timestamp", utcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("x-bili-timestamp", TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)); var signature = BuildSignatureString(request, Options.ClientSecret); request.Headers.Add("Authorization", signature); From bdafbea6049a45a253ae7cdfd9d10e54e3d124f4 Mon Sep 17 00:00:00 2001 From: Loongle Date: Tue, 1 Apr 2025 10:01:50 +0800 Subject: [PATCH 08/10] Remove invalid comment --- .../BilibiliAuthenticationHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 06ccfce6f..9e625df82 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -33,7 +33,7 @@ protected override string BuildChallengeUrl([NotNull] AuthenticationProperties p { var parameters = new Dictionary { - ["client_id"] = Options.ClientId, // Used instead of "client_id" + ["client_id"] = Options.ClientId, ["response_type"] = "code", ["gourl"] = redirectUri }; From 1cda6925ad5ae2d75ed355fc3613d2ff8fe7c653 Mon Sep 17 00:00:00 2001 From: Loongle Date: Tue, 1 Apr 2025 10:05:47 +0800 Subject: [PATCH 09/10] Remve blank character --- .../BilibiliAuthenticationHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index 9e625df82..e6abfda95 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -107,7 +107,7 @@ protected override async Task CreateTicketAsync( [NotNull] ClaimsIdentity identity, [NotNull] AuthenticationProperties properties, [NotNull] OAuthTokenResponse tokens) - { + { using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); request.Headers.Add("access-token", tokens.AccessToken); request.Headers.Add("x-bili-accesskeyid", Options.ClientId); From 5791811e64e8fde4511c63802d599151ca751056 Mon Sep 17 00:00:00 2001 From: Loongle Date: Wed, 2 Apr 2025 11:26:27 +0800 Subject: [PATCH 10/10] Add comments for gourl --- .../BilibiliAuthenticationHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs index e6abfda95..b1700e5bd 100644 --- a/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs +++ b/src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs @@ -35,7 +35,7 @@ protected override string BuildChallengeUrl([NotNull] AuthenticationProperties p { ["client_id"] = Options.ClientId, ["response_type"] = "code", - ["gourl"] = redirectUri + ["gourl"] = redirectUri // Used instead of "redirect_uri" }; foreach (var additionalParameter in Options.AdditionalAuthorizationParameters)