diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs index e365ad9f2..b06162497 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs @@ -37,15 +37,16 @@ public class IdentitySessionManager : DomainService, IIdentitySessionManager if (claimsPrincipal != null) { var userId = claimsPrincipal.FindUserId(); + var sessionId = claimsPrincipal.FindSessionId(); + if (!userId.HasValue || sessionId.IsNullOrWhiteSpace()) + { + return; + } + var tenantId = claimsPrincipal.FindTenantId(); using (CurrentTenant.Change(tenantId)) { - var sessionId = claimsPrincipal.FindSessionId(); - if (!userId.HasValue || sessionId.IsNullOrWhiteSpace()) - { - return; - } if (await IdentitySessionStore.ExistAsync(sessionId, cancellationToken)) { return; diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.Application.Contracts/LINGYUN/Abp/OpenIddict/Scopes/OpenIddictScopeCreateOrUpdateDto.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.Application.Contracts/LINGYUN/Abp/OpenIddict/Scopes/OpenIddictScopeCreateOrUpdateDto.cs index 03dd31ed5..1affce2a1 100644 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.Application.Contracts/LINGYUN/Abp/OpenIddict/Scopes/OpenIddictScopeCreateOrUpdateDto.cs +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.Application.Contracts/LINGYUN/Abp/OpenIddict/Scopes/OpenIddictScopeCreateOrUpdateDto.cs @@ -23,5 +23,5 @@ public abstract class OpenIddictScopeCreateOrUpdateDto : ExtensibleObject public Dictionary Properties { get; set; } = new Dictionary(); - public List Resources { get; set; } = new List(); + public HashSet Resources { get; set; } = new HashSet(); } diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/AbpOpenIddictAspNetCoreSessionModule.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/AbpOpenIddictAspNetCoreSessionModule.cs index 540fd0dcb..cb43c0309 100644 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/AbpOpenIddictAspNetCoreSessionModule.cs +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/AbpOpenIddictAspNetCoreSessionModule.cs @@ -2,6 +2,7 @@ using LINGYUN.Abp.Identity.Session; using LINGYUN.Abp.Identity.Session.AspNetCore; using Microsoft.Extensions.DependencyInjection; +using OpenIddict.Validation; using Volo.Abp.Modularity; using static OpenIddict.Abstractions.OpenIddictConstants; @@ -20,7 +21,8 @@ public class AbpOpenIddictAspNetCoreSessionModule : AbpModule builder.AddEventHandler(ProcessSignOutIdentitySession.Descriptor); builder.AddEventHandler(ProcessSignInIdentitySession.Descriptor); builder.AddEventHandler(RevocationIdentitySession.Descriptor); - builder.AddEventHandler(UserInfoIdentitySession.Descriptor); + builder.AddEventHandler(ServerValidationTokenCheckIdentitySession.Descriptor); + // builder.AddEventHandler(UserInfoIdentitySession.Descriptor); }); } @@ -36,5 +38,12 @@ public class AbpOpenIddictAspNetCoreSessionModule : AbpModule { options.PersistentSessionGrantTypes.Add(GrantTypes.Password); }); + + context.Services.Add(ValidationTokenCheckIdentitySession.Descriptor.ServiceDescriptor); + + Configure(options => + { + options.Handlers.Add(ValidationTokenCheckIdentitySession.Descriptor); + }); } } diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ServerValidationTokenCheckIdentitySession.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ServerValidationTokenCheckIdentitySession.cs new file mode 100644 index 000000000..9ce7b201b --- /dev/null +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ServerValidationTokenCheckIdentitySession.cs @@ -0,0 +1,43 @@ +using LINGYUN.Abp.Identity.Session; +using Microsoft.Extensions.Logging; +using OpenIddict.Server; +using System.Security.Principal; +using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; +using static OpenIddict.Abstractions.OpenIddictConstants; + +namespace LINGYUN.Abp.OpenIddict.AspNetCore.Session; +public class ServerValidationTokenCheckIdentitySession : IOpenIddictServerHandler +{ + protected ICurrentTenant CurrentTenant { get; } + protected IIdentitySessionChecker IdentitySessionChecker { get; } + + public static OpenIddictServerHandlerDescriptor Descriptor { get; } = + OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseSingletonHandler() + .SetOrder(OpenIddictServerHandlers.Protection.ValidatePrincipal.Descriptor.Order + 2_000) + .SetType(OpenIddictServerHandlerType.Custom).Build(); + + public ServerValidationTokenCheckIdentitySession( + ICurrentTenant currentTenant, + IIdentitySessionChecker identitySessionChecker) + { + CurrentTenant = currentTenant; + IdentitySessionChecker = identitySessionChecker; + } + + public async virtual ValueTask HandleAsync(OpenIddictServerEvents.ValidateTokenContext context) + { + var tenantId = context.Principal.FindTenantId(); + using (CurrentTenant.Change(tenantId)) + { + if (!await IdentitySessionChecker.ValidateSessionAsync(context.Principal)) + { + context.Logger.LogWarning("The token is no longer valid because the user's session expired."); + // Errors.InvalidToken ---> 401 + // Errors.ExpiredToken ---> 400 + context.Reject(Errors.InvalidToken, "The user session has expired."); + } + } + } +} diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/UserinfoIdentitySession.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/UserinfoIdentitySession.cs index 34a1fee20..23fbe6c4f 100644 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/UserinfoIdentitySession.cs +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/UserinfoIdentitySession.cs @@ -11,6 +11,7 @@ namespace LINGYUN.Abp.OpenIddict.AspNetCore.Session; /// /// UserInfoEndpoint 检查用户会话 /// +[Obsolete("UserInfoIdentitySession is outdated, please use the CheckIdentitySessionOnServerValidationToken")] public class UserInfoIdentitySession : IOpenIddictServerHandler { protected ICurrentTenant CurrentTenant { get; } diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ValidationTokenCheckIdentitySession.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ValidationTokenCheckIdentitySession.cs new file mode 100644 index 000000000..dca10e982 --- /dev/null +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore.Session/LINGYUN/Abp/OpenIddict/AspNetCore/Session/ValidationTokenCheckIdentitySession.cs @@ -0,0 +1,44 @@ +using LINGYUN.Abp.Identity.Session; +using Microsoft.Extensions.Logging; +using OpenIddict.Validation; +using System.Security.Principal; +using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; +using static OpenIddict.Abstractions.OpenIddictConstants; + +namespace LINGYUN.Abp.OpenIddict.AspNetCore.Session; +public class ValidationTokenCheckIdentitySession : IOpenIddictValidationHandler +{ + protected ICurrentTenant CurrentTenant { get; } + protected IIdentitySessionChecker IdentitySessionChecker { get; } + + public static OpenIddictValidationHandlerDescriptor Descriptor { get; } + = OpenIddictValidationHandlerDescriptor.CreateBuilder() + .UseSingletonHandler() + .SetOrder(OpenIddictValidationHandlers.Protection.ValidatePrincipal.Descriptor.Order + 2_000) + .SetType(OpenIddictValidationHandlerType.Custom) + .Build(); + + public ValidationTokenCheckIdentitySession( + ICurrentTenant currentTenant, + IIdentitySessionChecker identitySessionChecker) + { + CurrentTenant = currentTenant; + IdentitySessionChecker = identitySessionChecker; + } + + public async virtual ValueTask HandleAsync(OpenIddictValidationEvents.ValidateTokenContext context) + { + var tenantId = context.Principal.FindTenantId(); + using (CurrentTenant.Change(tenantId)) + { + if (!await IdentitySessionChecker.ValidateSessionAsync(context.Principal)) + { + context.Logger.LogWarning("The token is no longer valid because the user's session expired."); + // Errors.InvalidToken ---> 401 + // Errors.ExpiredToken ---> 400 + context.Reject(Errors.InvalidToken, "The user session has expired."); + } + } + } +} diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore/LINGYUN/Abp/OpenIddict/AspNetCore/Controllers/UserInfoController.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore/LINGYUN/Abp/OpenIddict/AspNetCore/Controllers/UserInfoController.cs deleted file mode 100644 index 71ac6a1ba..000000000 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.AspNetCore/LINGYUN/Abp/OpenIddict/AspNetCore/Controllers/UserInfoController.cs +++ /dev/null @@ -1,62 +0,0 @@ -using OpenIddict.Abstractions; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Security.Claims; -using Volo.Abp.Users; -using VoloUserInfoController = Volo.Abp.OpenIddict.Controllers.UserInfoController; - -namespace LINGYUN.Abp.OpenIddict.AspNetCore.Controllers; - -[ExposeServices( - typeof(VoloUserInfoController), - typeof(UserInfoController))] -public class UserInfoController : VoloUserInfoController -{ - protected async override Task> GetUserInfoClaims() - { - var user = await UserManager.GetUserAsync(User); - if (user == null) - { - return null; - } - - var claims = new Dictionary(StringComparer.Ordinal) - { - // Note: the "sub" claim is a mandatory claim and must be included in the JSON response. - [OpenIddictConstants.Claims.Subject] = await UserManager.GetUserIdAsync(user), - [AbpClaimTypes.SessionId] = CurrentUser.FindSessionId(), - }; - - if (User.HasScope(OpenIddictConstants.Scopes.Profile)) - { - claims[AbpClaimTypes.TenantId] = user.TenantId; - claims[OpenIddictConstants.Claims.PreferredUsername] = user.UserName; - claims[OpenIddictConstants.Claims.FamilyName] = user.Surname; - claims[OpenIddictConstants.Claims.GivenName] = user.Name; - } - - if (User.HasScope(OpenIddictConstants.Scopes.Email)) - { - claims[OpenIddictConstants.Claims.Email] = await UserManager.GetEmailAsync(user); - claims[OpenIddictConstants.Claims.EmailVerified] = await UserManager.IsEmailConfirmedAsync(user); - } - - if (User.HasScope(OpenIddictConstants.Scopes.Phone)) - { - claims[OpenIddictConstants.Claims.PhoneNumber] = await UserManager.GetPhoneNumberAsync(user); - claims[OpenIddictConstants.Claims.PhoneNumberVerified] = await UserManager.IsPhoneNumberConfirmedAsync(user); - } - - if (User.HasScope(OpenIddictConstants.Scopes.Roles)) - { - claims[OpenIddictConstants.Claims.Role] = await UserManager.GetRolesAsync(user); - } - - // Note: the complete list of standard claims supported by the OpenID Connect specification - // can be found here: http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims - - return claims; - } -}