@L["Login"]
diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
index 6ab8350b60..c17eb1e28f 100644
--- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
+++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
@@ -10,6 +10,8 @@ using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
using Volo.Abp.Account.Settings;
using Volo.Abp.Auditing;
using Volo.Abp.Identity;
@@ -53,18 +55,22 @@ public class LoginModel : AccountPageModel
protected AbpAccountOptions AccountOptions { get; }
protected IOptions
IdentityOptions { get; }
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; }
+ protected IWebHostEnvironment WebHostEnvironment { get; }
public bool ShowCancelButton { get; set; }
+ public bool ShowRequireMigrateSeedMessage { get; set; }
public LoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions accountOptions,
IOptions identityOptions,
- IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache)
+ IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache,
+ IWebHostEnvironment webHostEnvironment)
{
SchemeProvider = schemeProvider;
IdentityOptions = identityOptions;
AccountOptions = accountOptions.Value;
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache;
+ WebHostEnvironment = webHostEnvironment;
}
public virtual async Task OnGetAsync()
@@ -130,6 +136,17 @@ public class LoginModel : AccountPageModel
if (!result.Succeeded)
{
+ if (LoginInput.UserNameOrEmailAddress == IdentityDataSeedContributor.AdminUserNameDefaultValue &&
+ WebHostEnvironment.IsDevelopment())
+ {
+ var adminUser = await UserManager.FindByNameAsync(IdentityDataSeedContributor.AdminUserNameDefaultValue);
+ if (adminUser == null)
+ {
+ ShowRequireMigrateSeedMessage = true;
+ return Page();
+ }
+ }
+
Alerts.Danger(L["InvalidUserNameOrPassword"]);
return Page();
}
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo/Abp/BackgroundJobs/BackgroundJobRecordConsts.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo/Abp/BackgroundJobs/BackgroundJobRecordConsts.cs
index 4369bfcece..7cf4e651fe 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo/Abp/BackgroundJobs/BackgroundJobRecordConsts.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo/Abp/BackgroundJobs/BackgroundJobRecordConsts.cs
@@ -2,6 +2,11 @@
public static class BackgroundJobRecordConsts
{
+ ///
+ /// Default value: 96
+ ///
+ public static int MaxApplicationNameLength { get; set; } = 96;
+
///
/// Default value: 128
///
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobRecord.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobRecord.cs
index 66714af6d6..c01f933781 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobRecord.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobRecord.cs
@@ -6,6 +6,11 @@ namespace Volo.Abp.BackgroundJobs;
public class BackgroundJobRecord : AggregateRoot, IHasCreationTime
{
+ ///
+ /// Application name that scheduled this job.
+ ///
+ public virtual string ApplicationName { get; set; }
+
///
/// Type of the job.
/// It's AssemblyQualifiedName of job type.
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
index e29948cc95..c7dbd6fbef 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
@@ -34,10 +34,10 @@ public class BackgroundJobStore : IBackgroundJobStore, ITransientDependency
);
}
- public virtual async Task> GetWaitingJobsAsync(int maxResultCount)
+ public virtual async Task> GetWaitingJobsAsync(string applicationName, int maxResultCount)
{
return ObjectMapper.Map, List>(
- await BackgroundJobRepository.GetWaitingListAsync(maxResultCount)
+ await BackgroundJobRepository.GetWaitingListAsync(applicationName, maxResultCount)
);
}
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs
index b3c552c974..7e189df5c8 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs
@@ -2,11 +2,12 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.BackgroundJobs;
public interface IBackgroundJobRepository : IBasicRepository
{
- Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default);
+ Task> GetWaitingListAsync([CanBeNull] string applicationName, int maxResultCount, CancellationToken cancellationToken = default);
}
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs
index 5b51c8809d..53a2c53843 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs
@@ -22,6 +22,7 @@ public static class BackgroundJobsDbContextModelCreatingExtensions
b.ConfigureByConvention();
+ b.Property(x => x.ApplicationName).IsRequired(false).HasMaxLength(BackgroundJobRecordConsts.MaxApplicationNameLength);
b.Property(x => x.JobName).IsRequired().HasMaxLength(BackgroundJobRecordConsts.MaxJobNameLength);
b.Property(x => x.JobArgs).IsRequired().HasMaxLength(BackgroundJobRecordConsts.MaxJobArgsLength);
b.Property(x => x.TryCount).HasDefaultValue(0);
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs
index a2be3c6e1e..a81de3cdfb 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
@@ -22,17 +23,16 @@ public class EfCoreBackgroundJobRepository : EfCoreRepository> GetWaitingListAsync(
- int maxResultCount,
- CancellationToken cancellationToken = default)
+ public virtual async Task> GetWaitingListAsync([CanBeNull] string applicationName, int maxResultCount, CancellationToken cancellationToken = default)
{
- return await (await GetWaitingListQueryAsync(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
+ return await (await GetWaitingListQueryAsync(applicationName, maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
}
- protected virtual async Task> GetWaitingListQueryAsync(int maxResultCount)
+ protected virtual async Task> GetWaitingListQueryAsync([CanBeNull] string applicationName, int maxResultCount)
{
var now = Clock.Now;
return (await GetDbSetAsync())
+ .Where(t => t.ApplicationName == applicationName)
.Where(t => !t.IsAbandoned && t.NextTryTime <= now)
.OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount)
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs
index a3f46643fe..71a5680524 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
+using JetBrains.Annotations;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
@@ -23,17 +24,16 @@ public class MongoBackgroundJobRepository : MongoDbRepository> GetWaitingListAsync(
- int maxResultCount,
- CancellationToken cancellationToken = default)
+ public virtual async Task> GetWaitingListAsync([CanBeNull] string applicationName, int maxResultCount, CancellationToken cancellationToken = default)
{
- return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
+ return await (await GetWaitingListQuery(applicationName, maxResultCount, cancellationToken)).ToListAsync(GetCancellationToken(cancellationToken));
}
- protected virtual async Task> GetWaitingListQuery(int maxResultCount, CancellationToken cancellationToken = default)
+ protected virtual async Task> GetWaitingListQuery([CanBeNull] string applicationName, int maxResultCount, CancellationToken cancellationToken = default)
{
var now = Clock.Now;
return (await GetQueryableAsync(cancellationToken))
+ .Where(t => t.ApplicationName == applicationName)
.Where(t => !t.IsAbandoned && t.NextTryTime <= now)
.OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount)
diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs
index 02e4fa9d60..c62cb43309 100644
--- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs
+++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Linq;
+using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
@@ -23,12 +24,16 @@ public abstract class BackgroundJobRepository_Tests : Background
[InlineData(5)]
public async Task GetWaitingListAsync(int maxResultCount)
{
- var backgroundJobs = await _backgroundJobRepository.GetWaitingListAsync(maxResultCount);
+ var backgroundJobs = await _backgroundJobRepository.GetWaitingListAsync("App1", maxResultCount);
backgroundJobs.Count.ShouldBeGreaterThan(0);
backgroundJobs.Count.ShouldBeLessThanOrEqualTo(maxResultCount);
backgroundJobs.ForEach(j => j.IsAbandoned.ShouldBeFalse());
backgroundJobs.ForEach(j => j.NextTryTime.ShouldBeLessThanOrEqualTo(_clock.Now.AddSeconds(1))); //1 second tolerance
+
+ backgroundJobs.All(j => j.ApplicationName == "App1").ShouldBeTrue();
+ backgroundJobs.Any(j => j.ApplicationName == "App2").ShouldBeFalse();
+ backgroundJobs.Any(j => j.ApplicationName == null).ShouldBeFalse();
}
}
diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs
index 079a0ab3ea..f6f4c37e12 100644
--- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs
+++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs
@@ -26,6 +26,7 @@ public class BackgroundJobsTestDataBuilder : ITransientDependency
await _backgroundJobRepository.InsertAsync(
new BackgroundJobRecord(_testData.JobId1)
{
+ ApplicationName = "App1",
JobName = "TestJobName",
JobArgs = "{ value: 1 }",
NextTryTime = _clock.Now.Subtract(TimeSpan.FromMinutes(1)),
@@ -40,6 +41,7 @@ public class BackgroundJobsTestDataBuilder : ITransientDependency
await _backgroundJobRepository.InsertAsync(
new BackgroundJobRecord(_testData.JobId2)
{
+ ApplicationName = "App2",
JobName = "TestJobName",
JobArgs = "{ value: 2 }",
NextTryTime = _clock.Now.AddMinutes(42),
@@ -54,6 +56,7 @@ public class BackgroundJobsTestDataBuilder : ITransientDependency
await _backgroundJobRepository.InsertAsync(
new BackgroundJobRecord(_testData.JobId3)
{
+ ApplicationName = "App1",
JobName = "TestJobName",
JobArgs = "{ value: 3 }",
NextTryTime = _clock.Now,
diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/ExtensionGrants/MyTokenExtensionGrant.cs b/modules/openiddict/app/OpenIddict.Demo.Server/ExtensionGrants/MyTokenExtensionGrant.cs
index b5167621ef..12e587b65b 100644
--- a/modules/openiddict/app/OpenIddict.Demo.Server/ExtensionGrants/MyTokenExtensionGrant.cs
+++ b/modules/openiddict/app/OpenIddict.Demo.Server/ExtensionGrants/MyTokenExtensionGrant.cs
@@ -19,7 +19,17 @@ public class MyTokenExtensionGrant : ITokenExtensionGrant
public const string ExtensionGrantName = "MyTokenExtensionGrant";
public string Name => ExtensionGrantName;
+
public async Task HandleAsync(ExtensionGrantContext context)
+ {
+ // You can get a new token using any of the following methods based on your business.
+ // They are just examples. You can implement your own logic here.
+
+ return await HandleUserAccessTokenAsync(context);
+ return await HandleUserApiKeyAsync(context);
+ }
+
+ public async Task HandleUserAccessTokenAsync(ExtensionGrantContext context)
{
var userToken = context.Request.GetParameter("token").ToString();
@@ -33,6 +43,9 @@ public class MyTokenExtensionGrant : ITokenExtensionGrant
}!));
}
+ // We will validate the user token
+ // The Token is issued by the OpenIddict server, So we can validate it using the introspection endpoint
+
var transaction = await context.HttpContext.RequestServices.GetRequiredService().CreateTransactionAsync();
transaction.EndpointType = OpenIddictServerEndpointType.Introspection;
transaction.Request = new OpenIddictRequest
@@ -71,17 +84,92 @@ public class MyTokenExtensionGrant : ITokenExtensionGrant
}));
}
+ // We have validated the user token and got the user id
+
var userId = principal.FindUserId();
var userManager = context.HttpContext.RequestServices.GetRequiredService();
var user = await userManager.GetByIdAsync(userId.Value);
var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService>();
var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
- claimsPrincipal.SetScopes(principal.GetScopes());
- claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));
+
+ // Prepare the scopes
+ var scopes = GetScopes(context);
+
+ claimsPrincipal.SetScopes(scopes);
+ claimsPrincipal.SetResources(await GetResourcesAsync(context, scopes));
await context.HttpContext.RequestServices.GetRequiredService().HandleAsync(context.Request, principal);
return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
}
+
+ protected async Task HandleUserApiKeyAsync(ExtensionGrantContext context)
+ {
+ var userApiKey = context.Request.GetParameter("user_api_key").ToString();
+
+ if (string.IsNullOrEmpty(userApiKey))
+ {
+ return new ForbidResult(
+ new[] {OpenIddictServerAspNetCoreDefaults.AuthenticationScheme},
+ properties: new AuthenticationProperties(new Dictionary
+ {
+ [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest
+ }!));
+ }
+
+ // Here we can validate the user API key and get the user id
+ if (false) // Add your own logic here
+ {
+ // If the user API key is invalid
+ return new ForbidResult(
+ new[] {OpenIddictServerAspNetCoreDefaults.AuthenticationScheme},
+ properties: new AuthenticationProperties(new Dictionary
+ {
+ [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest
+ }!));
+ }
+
+ // Add your own logic to get the user by API key
+ var userManager = context.HttpContext.RequestServices.GetRequiredService();
+ var user = await userManager.FindByNameAsync("admin");
+ if (user == null)
+ {
+ return new ForbidResult(
+ new[] {OpenIddictServerAspNetCoreDefaults.AuthenticationScheme},
+ properties: new AuthenticationProperties(new Dictionary
+ {
+ [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest
+ }!));
+ }
+
+ // Create a principal for the user
+ var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService>();
+ var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
+
+ // Prepare the scopes
+ var scopes = GetScopes(context);
+
+ claimsPrincipal.SetScopes(scopes);
+ claimsPrincipal.SetResources(await GetResourcesAsync(context, scopes));
+ await context.HttpContext.RequestServices.GetRequiredService().HandleAsync(context.Request, claimsPrincipal);
+ return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
+ }
+
+ protected ImmutableArray GetScopes(ExtensionGrantContext context)
+ {
+ // Prepare the scopes
+ // The scopes must be defined in the OpenIddict server
+
+ // If you want to get the scopes from the request, you have to add `scope` parameter in the request
+ // scope: AbpAPI profile roles email phone offline_access
+
+ //var scopes = context.Request.GetScopes();
+
+ // If you want to set the scopes here, you can use the following code
+ var scopes = new[] { "AbpAPI", "profile", "roles", "email", "phone", "offline_access" }.ToImmutableArray();
+
+ return scopes;
+ }
+
private async Task> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray scopes)
{
var resources = new List();