Hi,
I suppose you are talking about the Volo.Abp.Users.Abstractions package. We created it to not depend on the Microsoft Identity library from our other modules and make the Identity library replaceable in advanced scenarios.
We don't plan and we don't want to create abstractions for organization units and roles. We already have abstractions for permissions (and settings, features, etc - these are defined in the core abp framework packages, while the database implementation are in separate modules). You don't need to have a reference to the Permission Management module, for example, to check a permission.
We don't think it is true to create such a detailed abstraction. OU and roles are mainly used to organize permissions and your module should only need to the permission system dependency (it already has). These details are internals of the Identity module.
Creating an abstraction is a very serious decision and has important costs. If we create abstractions for OUs and roles, we implicitly force all the implementations should support these systems (in ideal). Abstractions should be minimal and should have very few assumptions about the implementations. If we completely wrap all Identity details, no point to make an abstraction, we directly use it.
Finally, such abstractions are useful while developing a modular framework. But you probably don't need it. You can directly depend on the Identity module from your other modules, especially if you don't need a system that makes possible to change the Identity without effecting other modules. Even if you need it, creating such a detailed abstraction may have a bigger cost than changing the Identity module when you need it in the future.
With that, if the integration effort is more or less the same as keeping IDS4 alive, without tapping on new features that Duende has in stock and provided the API remains largely the same for the ABP use cases, then why not?
We were considering this scenario. If we provide an option to start a new solution with IDS installed, then it is a huge effort to support multiple auth server option. If we only upgrade packages to Duende IDS for existing customer projects, it also may not worth effort. We have time to make the final decision. It is mostly based on how many customers will want to continue with Duende IDS. We will see, but we can't promise unfortunately.
Any plans to keep the IDS support option? Any plans for Commercial IDS support?
We are not removing IDS packages and will continue to release new versions of IDS related Nuget/NPM packages. That means you won't have an issue while upgrading to v6.0 (when it is released). We will continue to fix bugs in our packages for a while. ABP 7.0 will be based on .NET 7. If IDS continue to work with .NET 7, we will continue to ship nuget packages for our IDS integration.
BTW, IDS itself is canceling support for the open source IDS in the end of this year. They are moved to Duende IDS you know. We won't migrate to Duende IDS.
Hi,
IdentityUser
class is not in your application, it comes from the Identity module as you know. So, you can not directly change its source code to add a navigation collection (unless you include Identity modules's source code into your solution).
So, when you don't add ICollection<T>
to the IdentityUser
, there is no way to define many-to-many relationship as you want. Not possible to do it with fluent api and defining collection only in one side. EF Core doesn't allow to it. You can see these links for more info:
The best solution I can suggest is to manually create the relation entity. I tried with the following entities:
public class Book : AggregateRoot<int>
{
public string Name { get; set; }
public Collection<UserBook> UserBooks { get; set; }
}
public class UserBook : BasicAggregateRoot<int>
{
public IdentityUser User { get; set; }
public Book Book { get; set; }
}
My purpose is to establish a many-to-many relation between IdentityUser
and Book
entities. So, I defined UserBook
as a relation entity. Then mapped it like that:
builder.Entity<UserBook>(b =>
{
b.ToTable("UserBooks");
b.ConfigureByConvention();
b.HasOne(x => x.User).WithMany().HasForeignKey("UserId");
b.HasOne(x => x.Book).WithMany(x => x.UserBooks).HasForeignKey("BookId");
});
The relation table is created when I add a new migration. So, now you can include Users while querying books. However, you can not do vice verse. You should separately query books of a user or perform a LINQ JOIN query yourself since Include won't work (no navigation collection on the IdentityUser
entity).
IFeatureChecker
is only for checking features for the current user and has limitations due to its design and purpose.
Use IFeatureManager
as documented here: https://docs.abp.io/en/abp/latest/Modules/Feature-Management#ifeaturemanager
But when we will place Modules in different service, what we need to do so IBookService will be resolved to HttpApiClient, so call will be made over http?
Yest, that's the design of ABP's modularity. This document explains it well: https://docs.abp.io/en/abp/latest/Best-Practices/Module-Architecture It explains all the scenarios.
The second question is what to do when we will add authorization to endpoints in IBookService
Authentication and authorization is automated when you properly configure the client and the server. Create a MVC tiered application. In this setup, MVC UI uses the app service interfaces, but it actually make an HTTP request to the HTTP API server by authenticating and authorizing.
Console test app in the startup template also does that: https://github.com/abpframework/abp/tree/dev/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.HttpApi.Client.ConsoleTestApp It uses resource owner password authentication, but you can easily configure client-secret auth too.
Another document: https://docs.abp.io/en/abp/latest/Samples/Microservice-Demo#identityserver-client here, blogging microservice calls the identity microservice and this section shows the auth config.
We suggest client-secret auth when you want to consume a microservice from a background worker/job.
Hi,
ICurrentTenant.Change
is the only way to operate on a specific tenant in a background worker. I can recommend to create a separate console application for the background workers and run only a single instance of that application. Otherwise, if you make it a part of a service, you should care when you run multiple instances of that service - the worker may work on the same data which may cause duplications.
Disabling the tenancy filter is needed if you want to query from all tenants. It can only work for "shared database" approach. It can't work if a tenant has a seperate database. However, if you want to query a list of tenants (from the AbpTenants table), no need to disable the tenancy filter, because the Tenant entity is not multi-tenant.
In your background worker app, you can add a reference to the Volo.SaaS.EntityFrameworkCore and set the connection string for the saas database. Alternatively, you can perform a call to the SaaS service if you don't want to access the SaaS db from the worker app. But, I suggest to use the db.
My original question was around the part regarding sending requests to remote systems that require require login sessions, these systems would all be on separate servers that I would not control.
Hi. Shouldn't you ask this to that system's maintainers? Because we can't know how they are authenticated. If every tenant has different connection information, you can define a tenant based setting and store that information in the setting. Settings can be encrypted too.
Thanks for the suggestion. I've added it to the product backlog to consider later.
Hi Vicent,
My main motivation of designing IssueLabel as ValueObject is to show its usage. However, when it comes to choose between entities and value objects highly depends on your domain.
For such relation tables, you can go with value objects or entities, actually doesn't matter much because they have no business. If you think a relation object can change later, then you should make it as entity (since value objects are immutable in ideal). For example, assume that we have a UserRole class with UserId and RoleId, then this can be value object or entity, doesn't matter much. However, if you add a IsActive
property to UserRole classi, which is enabled/disabled to temporary disable a role for a user, then this should be entity, not a value object.
Value objects are ideal to associate domain logic and business to simple values. As a common example, a Money value object can be useful instead of a decimal Amount
property for an entity (if you define Money, then Amount's type becomes Money which explicitly shows that this is a money). Also, you can add some methods on the Money object to collect the money domain logic in a single place.