diff --git a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationConstants.cs b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationConstants.cs
index d6188fc4f..54b9cb98f 100644
--- a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationConstants.cs
+++ b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationConstants.cs
@@ -25,5 +25,17 @@ public static class Claims
/// The user's gender. F: Female; M: Male.
///
public const string Gender = "urn:alipay:gender";
+
+ ///
+ /// OpenID is the unique identifier for Alipay users at the application level.
+ /// See https://opendocs.alipay.com/mini/0ai2i6
+ ///
+ public const string OpenId = "urn:alipay:open_id";
+
+ ///
+ /// The internal identifier for Alipay users will no longer be independently available going forward and will be replaced by OpenID.
+ /// See https://opendocs.alipay.com/common/0ai736
+ ///
+ public const string UserId = "urn:alipay:user_id";
}
}
diff --git a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationHandler.cs b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationHandler.cs
index b33da5630..7e1e31d48 100644
--- a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationHandler.cs
+++ b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationHandler.cs
@@ -44,6 +44,16 @@ protected override Task HandleRemoteAuthenticateAsync()
return base.HandleRemoteAuthenticateAsync();
}
+ private const string SignType = "RSA2";
+
+ private void AddCertificateSignatureParameters(SortedDictionary parameters)
+ {
+ ArgumentNullException.ThrowIfNull(Options.ApplicationCertificateSn);
+ ArgumentNullException.ThrowIfNull(Options.RootCertificateSn);
+ parameters["app_cert_sn"] = Options.ApplicationCertificateSn;
+ parameters["alipay_root_cert_sn"] = Options.RootCertificateSn;
+ }
+
protected override async Task ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context)
{
// See https://opendocs.alipay.com/apis/api_9/alipay.system.oauth.token for details.
@@ -55,10 +65,16 @@ protected override async Task ExchangeCodeAsync([NotNull] OA
["format"] = "JSON",
["grant_type"] = "authorization_code",
["method"] = "alipay.system.oauth.token",
- ["sign_type"] = "RSA2",
+ ["sign_type"] = SignType,
["timestamp"] = TimeProvider.GetUtcNow().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
["version"] = "1.0",
};
+
+ if (Options.UseCertificateSignatures)
+ {
+ AddCertificateSignatureParameters(tokenRequestParameters);
+ }
+
tokenRequestParameters.Add("sign", GetRSA2Signature(tokenRequestParameters));
// PKCE https://tools.ietf.org/html/rfc7636#section-4.5, see BuildChallengeUrl
@@ -103,10 +119,16 @@ protected override async Task CreateTicketAsync(
["charset"] = "utf-8",
["format"] = "JSON",
["method"] = "alipay.user.info.share",
- ["sign_type"] = "RSA2",
+ ["sign_type"] = SignType,
["timestamp"] = TimeProvider.GetUtcNow().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
["version"] = "1.0",
};
+
+ if (Options.UseCertificateSignatures)
+ {
+ AddCertificateSignatureParameters(parameters);
+ }
+
parameters.Add("sign", GetRSA2Signature(parameters));
var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, parameters);
diff --git a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationOptions.cs b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationOptions.cs
index 08677ddd5..0552a69c7 100644
--- a/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationOptions.cs
+++ b/src/AspNet.Security.OAuth.Alipay/AlipayAuthenticationOptions.cs
@@ -29,5 +29,46 @@ public AlipayAuthenticationOptions()
ClaimActions.MapJsonKey(Claims.Gender, "gender");
ClaimActions.MapJsonKey(Claims.Nickname, "nick_name");
ClaimActions.MapJsonKey(Claims.Province, "province");
+ ClaimActions.MapJsonKey(Claims.OpenId, "open_id");
+
+ // https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/pull/1131#discussion_r2657531257
+ ClaimActions.MapJsonKey("urn:alipay:user_id", "user_id");
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to use certificate mode for signing calls.
+ /// https://opendocs.alipay.com/common/057k53?pathHash=e18d6f77#%E8%AF%81%E4%B9%A6%E6%A8%A1%E5%BC%8F
+ ///
+ public bool UseCertificateSignatures { get; set; }
+
+ ///
+ /// Gets or sets the optional ID for your Sign in with Application Public Key Certificate SN(app_cert_sn).
+ /// https://opendocs.alipay.com/support/01raux
+ ///
+ public string? ApplicationCertificateSn { get; set; }
+
+ ///
+ /// Gets or sets the optional ID for your Sign in with Alipay Root Certificate SN.
+ /// https://opendocs.alipay.com/support/01rauy
+ ///
+ public string? RootCertificateSn { get; set; }
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+
+ if (UseCertificateSignatures)
+ {
+ if (string.IsNullOrEmpty(ApplicationCertificateSn))
+ {
+ throw new ArgumentException($"The '{nameof(ApplicationCertificateSn)}' option must be provided if the '{nameof(UseCertificateSignatures)}' option is set to true.", nameof(ApplicationCertificateSn));
+ }
+
+ if (string.IsNullOrEmpty(RootCertificateSn))
+ {
+ throw new ArgumentException($"The '{nameof(RootCertificateSn)}' option must be provided if the '{nameof(UseCertificateSignatures)}' option is set to true.", nameof(RootCertificateSn));
+ }
+ }
}
}