Skip to content

Add Douyin provider #1024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion AspNet.Security.OAuth.Providers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{C2CA4B38-A
docs\digitalocean.md = docs\digitalocean.md
docs\discord.md = docs\discord.md
docs\docusign.md = docs\docusign.md
douyin.md = douyin.md
docs\dropbox.md = docs\dropbox.md
docs\ebay.md = docs\ebay.md
docs\eveonline.md = docs\eveonline.md
Expand Down
3 changes: 1 addition & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ covered by the section above.
| Bitbucket | _Optional_ | [Documentation](bitbucket.md "Bitbucket provider documentation") |
| DigitalOcean | _Optional_ | [Documentation](digitalocean.md "DigitalOcean provider documentation") |
| Discord | _Optional_ | [Documentation](discord.md "Discord provider documentation") |
| Docusign | **Required** | [Documentation](docusign.md "Docusign provider documentation") |
| Douyin | _Optional_ | [Documentation](douyin.md "Douyin provider documentation") |
| Docusign | **Required** | [Documentation](docusign.md "Docusign provider documentation") |
| eBay | **Required** | [Documentation](ebay.md "eBay provider documentation") |
| EVEOnline | _Optional_ | [Documentation](eveonline.md "EVEOnline provider documentation") |
| Foursquare | _Optional_ | [Documentation](foursquare.md "Foursquare provider documentation") |
Expand Down
20 changes: 0 additions & 20 deletions docs/douyin.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageValidationBaselineVersion>9.1.0</PackageValidationBaselineVersion>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>

<!-- TODO Remove once published to NuGet.org -->
<PropertyGroup>
<DisablePackageBaselineValidation>true</DisablePackageBaselineValidation>
</PropertyGroup>

<PropertyGroup>
<Description>ASP.NET Core security middleware enabling Douyin authentication.</Description>
<Authors>Loongle Tse</Authors>
Expand Down
54 changes: 5 additions & 49 deletions src/AspNet.Security.OAuth.Douyin/DouyinAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,6 @@ public DouyinAuthenticationHandler(
{
}

private const string AuthCode = "auth_code";

protected override Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
{
if (TryStandardizeRemoteAuthenticateQuery(Request.Query, out var queryString))
{
Request.QueryString = queryString;
}

return base.HandleRemoteAuthenticateAsync();
}

protected override async Task<OAuthTokenResponse> ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context)
{
// See https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/account-permission/get-access-token for details.
Expand Down Expand Up @@ -126,19 +114,19 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
/// <summary>
/// Check the code sent back by server for potential server errors.
/// </summary>
/// <param name="element">Main part of json document from response</param>
/// <param name="element">Main part of JSON document from response</param>
/// <param name="errorCode">Returned error_code from server</param>
/// <remarks>See https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/status-code for details.</remarks>
/// <returns>True if succeed, otherwise false.</returns>
private static bool ValidateReturnCode(JsonElement element, out int errorCode)
{
if (!element.TryGetProperty("error_code", out JsonElement errorCodeElement))
errorCode = 0;

if (element.TryGetProperty("error_code", out JsonElement errorCodeElement))
{
errorCode = 0;
return true;
errorCode = errorCodeElement.GetInt32()!;
}

errorCode = errorCodeElement.GetInt32()!;
return errorCode == 0;
}

Expand Down Expand Up @@ -166,38 +154,6 @@ protected override string BuildChallengeUrl([NotNull] AuthenticationProperties p
return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters);
}

private static bool TryStandardizeRemoteAuthenticateQuery(IQueryCollection query, out QueryString queryString)
{
if (!query.TryGetValue(AuthCode, out var authCode))
{
queryString = default;
return false;
}

// Before: mydomain/signin-douyin?auth_code=xxx&state=xxx&...
// After: mydomain/signin-douyin?code=xxx&state=xxx&...
var queryParams = new List<KeyValuePair<string, StringValues>>(query.Count)
{
new("code", authCode)
};
foreach (var item in query)
{
switch (item.Key)
{
case "code":
case AuthCode: // No need in fact, skip it
break;

default:
queryParams.Add(item);
break;
}
}

queryString = QueryString.Create(queryParams);
return true;
}

private static partial class Log
{
internal static async Task UserProfileErrorAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
Expand Down
31 changes: 31 additions & 0 deletions test/AspNet.Security.OAuth.Providers.Tests/Douyin/DouyinTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* for more information concerning the license and the contributors participating to this project.
*/

using AspNet.Security.OAuth.Xero;
using Microsoft.AspNetCore.WebUtilities;

namespace AspNet.Security.OAuth.Douyin;
Expand All @@ -27,4 +28,34 @@ protected internal override void RegisterAuthentication(AuthenticationBuilder bu
[InlineData("urn:douyin:nickname", "TestAccount")]
public async Task Can_Sign_In_Using_Douyin(string claimType, string claimValue)
=> await AuthenticateUserAndAssertClaimValue(claimType, claimValue);

[Fact]
public async Task BuildChallengeUrl_Generates_Correct_Url()
{
// Arrange
var options = new DouyinAuthenticationOptions();

var redirectUrl = "https://my-site.local/signin-douyin";

// Act
Uri actual = await BuildChallengeUriAsync(
options,
redirectUrl,
(options, loggerFactory, encoder) => new DouyinAuthenticationHandler(options, loggerFactory, encoder));

// Assert
actual.ShouldNotBeNull();
actual.ToString().ShouldStartWith("https://open.douyin.com/platform/oauth/connect/");

var query = QueryHelpers.ParseQuery(actual.Query);

query.ShouldContainKey("state");
query.ShouldContainKeyAndValue("client_key", options.ClientId);
query.ShouldContainKeyAndValue("redirect_uri", redirectUrl);
query.ShouldContainKeyAndValue("response_type", "code");
query.ShouldContainKeyAndValue("scope", "user_info");

query.ShouldNotContainKey(OAuthConstants.CodeChallengeKey);
query.ShouldNotContainKey(OAuthConstants.CodeChallengeMethodKey);
}
}