diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj b/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj
index f5a976063..b7640bde4 100644
--- a/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj
+++ b/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj
@@ -12,12 +12,12 @@
-
+
-
+
diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Queries/ThirdPartyUserByUserIdQuery.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Queries/ThirdPartyUserByUserIdQuery.cs
new file mode 100644
index 000000000..c64497a14
--- /dev/null
+++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Queries/ThirdPartyUserByUserIdQuery.cs
@@ -0,0 +1,9 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the Apache License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Auth.Service.Admin.Application.Subjects.Queries;
+
+public record ThirdPartyUserByUserIdQuery(Guid UserId, Guid ThirdPartyIdpId) : Query
+{
+ public override UserModel? Result { get; set; }
+}
diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/QueryHandler.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/QueryHandler.cs
index 3b5104d79..99ee76bf9 100644
--- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/QueryHandler.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/QueryHandler.cs
@@ -434,6 +434,22 @@ public async Task GetThirdPartyUserAsync(ThirdPartyUserQuery query)
query.Result = userModel;
}
+ [EventHandler]
+ public async Task GetThirdPartyUserByUserIdAsync(ThirdPartyUserByUserIdQuery query)
+ {
+ var tpUser = await _authDbContext.Set()
+ .Include(tpu => tpu.User)
+ .FirstOrDefaultAsync(tpu => tpu.ThirdPartyIdpId == query.ThirdPartyIdpId && tpu.UserId == query.UserId);
+ var userModel = tpUser?.User?.Adapt();
+
+ if (tpUser != null && tpUser.User != null && userModel != null)
+ {
+ userModel.ClaimData = tpUser.ClaimData;
+ }
+
+ query.Result = userModel;
+ }
+
#endregion
#region ThirdPartyIdp
diff --git a/src/Services/Masa.Auth.Service.Admin/Services/ThirdPartyUserService.cs b/src/Services/Masa.Auth.Service.Admin/Services/ThirdPartyUserService.cs
index ba7685be2..a37b44cfb 100644
--- a/src/Services/Masa.Auth.Service.Admin/Services/ThirdPartyUserService.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Services/ThirdPartyUserService.cs
@@ -35,6 +35,18 @@ private async Task GetDetailAsync(IEventBus eventBus, [
return query.Result;
}
+ [AllowAnonymous]
+ private async Task GetByUserIdAsync(IEventBus eventBus, [FromQuery] string scheme, Guid userId)
+ {
+ var identityProviderQuery = new IdentityProviderBySchemeQuery(scheme);
+ await eventBus.PublishAsync(identityProviderQuery);
+ var identityProvider = identityProviderQuery.Result;
+
+ var query = new ThirdPartyUserByUserIdQuery(userId, identityProvider.Id);
+ await eventBus.PublishAsync(query);
+ return query.Result;
+ }
+
private async Task UpsertThirdPartyUserExternalAsync(IEventBus eventBus, UpsertThirdPartyUserModel model)
{
var query = new UpsertThirdPartyUserExternalCommand(model);
diff --git a/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/PssoPhoneNumberGrantValidator.cs b/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/PssoPhoneNumberGrantValidator.cs
new file mode 100644
index 000000000..caa4a8e55
--- /dev/null
+++ b/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/PssoPhoneNumberGrantValidator.cs
@@ -0,0 +1,75 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the Apache License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Auth.Web.Sso.Infrastructure.Validations;
+
+public class PssoPhoneNumberGrantValidator : IExtensionGrantValidator
+{
+ IAuthClient _authClient;
+ LocalLoginByPhoneNumberAgent _localLoginByPhoneNumber;
+
+ public string GrantType { get; } = "psso_phone";
+
+ public PssoPhoneNumberGrantValidator(IAuthClient authClient, LocalLoginByPhoneNumberAgent localLoginByPhoneNumber)
+ {
+ _authClient = authClient;
+ _localLoginByPhoneNumber = localLoginByPhoneNumber;
+ }
+
+ public async Task ValidateAsync(ExtensionGrantValidationContext context)
+ {
+ var phoneNumber = context.Request.Raw["PhoneNumber"];
+ var spToken = context.Request.Raw["SpToken"];
+ if (string.IsNullOrEmpty(phoneNumber) || string.IsNullOrEmpty(spToken))
+ {
+ context.Result = new GrantValidationResult
+ {
+ IsError = true,
+ Error = "Must provide phone number and spToken",
+ ErrorDescription = "Must provide phone number and spToken"
+ };
+ return;
+ }
+
+ var (success, errorMsg) = await _localLoginByPhoneNumber.VerifyPhoneWithTokenAsync(phoneNumber, spToken);
+ if (success)
+ {
+ var user = await _authClient.UserService.GetByPhoneNumberAsync(phoneNumber);
+ if (user is null)
+ {
+ context.Result = new GrantValidationResult
+ {
+ IsError = true,
+ Error = $"User {phoneNumber} does not exist",
+ ErrorDescription = errorMsg
+ };
+ }
+ else
+ {
+ var authUser = await _authClient.UserService.GetThirdPartyUserByUserIdAsync(new GetThirdPartyUserByUserIdModel
+ {
+ Scheme = "Psso",
+ UserId = user.Id
+ });
+
+ var claims = new List();
+ if (authUser != null)
+ {
+ foreach (var item in authUser.ClaimData)
+ {
+ claims.Add(new Claim(item.Key, item.Value));
+ }
+ }
+
+ context.Result = new GrantValidationResult(user.Id.ToString(), "local", claims);
+ }
+ }
+ else
+ context.Result = new GrantValidationResult
+ {
+ IsError = true,
+ Error = errorMsg,
+ ErrorDescription = errorMsg
+ };
+ }
+}
diff --git a/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj b/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj
index abe0b8c30..942690175 100644
--- a/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj
+++ b/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj
@@ -24,7 +24,7 @@
-
+