Browse Source

Merge branch 'dev' into blazor-ui-page-header

pull/5836/head
İlkay İlknur 5 years ago
parent
commit
c3be9fa0df
  1. 3
      .gitignore
  2. 2
      docs/en/Repositories.md
  3. 2
      docs/en/Tutorials/Part-10.md
  4. 10
      docs/en/Tutorials/Part-2.md
  5. 20
      docs/en/Tutorials/Part-3.md
  6. 3
      docs/en/Tutorials/Part-4.md
  7. 8
      docs/en/Tutorials/Part-5.md
  8. 4
      docs/en/Tutorials/Part-7.md
  9. 14
      docs/en/Tutorials/Part-9.md
  10. BIN
      docs/en/Tutorials/images/bookstore-authors-blazor-ui.png
  11. 24
      docs/en/UI/AspNetCore/JavaScript-API/Auth.md
  12. 56
      docs/en/UI/AspNetCore/JavaScript-API/Block-Busy.md
  13. 49
      docs/en/UI/AspNetCore/JavaScript-API/CurrentUser.md
  14. 117
      docs/en/UI/AspNetCore/JavaScript-API/DOM.md
  15. 15
      docs/en/UI/AspNetCore/JavaScript-API/Features.md
  16. 28
      docs/en/UI/AspNetCore/JavaScript-API/Index.md
  17. 49
      docs/en/UI/AspNetCore/JavaScript-API/Logging.md
  18. 40
      docs/en/UI/AspNetCore/JavaScript-API/ResourceLoader.md
  19. 28
      docs/en/docs-nav.json
  20. BIN
      docs/en/images/ui-busy.png
  21. 8
      framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs
  22. 9
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
  23. 6
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml
  24. 56
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs
  25. 2
      modules/cms-kit/host/Volo.CmsKit.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs
  26. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs
  27. 27
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs
  28. 12
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceConsts.cs
  29. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceEto.cs
  30. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourcePropertyConsts.cs
  31. 7
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceScopeConsts.cs
  32. 20
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceSecretConsts.cs
  33. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiScopeConsts.cs
  34. 11
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiResourceConsts.cs
  35. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiScopePropertyConsts.cs
  36. 7
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientClaimConsts.cs
  37. 26
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientConsts.cs
  38. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientCorsOriginConsts.cs
  39. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientGrantTypeConsts.cs
  40. 12
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientSecretConsts.cs
  41. 19
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesConsts.cs
  42. 6
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesEto.cs
  43. 22
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Grants/PersistedGrantConsts.cs
  44. 8
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceConsts.cs
  45. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/IdentityResources/IdentityResourcePropertyConsts.cs
  46. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/en.json
  47. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/zh-Hans.json
  48. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/ObjectExtending/IdentityServerModuleExtensionConfiguration.cs
  49. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/ObjectExtending/IdentityServerModuleExtensionConsts.cs
  50. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj
  51. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs
  52. 3
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs
  53. 37
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedSigningAlgorithmsConverter.cs
  54. 72
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResource.cs
  55. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceClaim.cs
  56. 39
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceProperty.cs
  57. 38
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceScope.cs
  58. 20
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceSecret.cs
  59. 37
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiScopeClaim.cs
  60. 15
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/IApiResourceRepository.cs
  61. 63
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScope.cs
  62. 31
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScopeClaim.cs
  63. 39
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScopeProperty.cs
  64. 38
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/IApiScopeeRepository.cs
  65. 10
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs
  66. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs
  67. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientProperty.cs
  68. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs
  69. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/IClientRepository.cs
  70. 6
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowCodes.cs
  71. 21
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs
  72. 12
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrant.cs
  73. 15
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs
  74. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs
  75. 52
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResource.cs
  76. 8
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceClaim.cs
  77. 39
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceProperty.cs
  78. 105
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerAutoMapperProfile.cs
  79. 60
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs
  80. 19
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/AbpIdentityServerEfCoreQueryableExtensions.cs
  81. 65
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs
  82. 75
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs
  83. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs
  84. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs
  85. 29
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs
  86. 29
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs
  87. 227
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs
  88. 52
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs
  89. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs
  90. 5
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs
  91. 11
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs
  92. 8
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs
  93. 5
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs
  94. 19
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs
  95. 57
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs
  96. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs
  97. 2
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs
  98. 42
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs
  99. 2
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs
  100. 25
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs

3
.gitignore

@ -305,3 +305,6 @@ modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Logs/
/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package-lock.json
abp-build-config.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/Pages/Test/
# Identity Server temp signature file
tempkey.jwk

2
docs/en/Repositories.md

@ -270,7 +270,7 @@ This method is suggested;
For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppService` base class (see the [application services](Application-Services.md) document).
### Option-3: Custom Repository Methods
### Option-4: Custom Repository Methods
You can always create custom repository methods and use the database provider specific APIs, like async extension methods here. See [EF Core](Entity-Framework-Core.md) or [MongoDb](MongoDB.md) document for more info about the custom repositories.

2
docs/en/Tutorials/Part-10.md

@ -38,7 +38,7 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
We have created `Book` and `Author` functionalities for the book store application. However, currently there is no relation between these entities.
In this tutorial, we will establish a **1 to N** relation between the `Book` and the `Author`.
In this tutorial, we will establish a **1 to N** relation between the `Author` and the `Book` entities.
## Add Relation to The Book Entity

10
docs/en/Tutorials/Part-2.md

@ -583,7 +583,7 @@ When you click to the Books menu item under the Book Store parent, you are being
We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including the Bootstrap.
ABP Framework provides a generic base class, `BlazoriseCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `BlazoriseCrudPageBase` to automate the standard CRUD stuff.
ABP Framework provides a generic base class, `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff.
Open the `Books.razor` and replace the content as the following:
@ -595,7 +595,7 @@ Open the `Books.razor` and replace the content as the following:
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<BookStoreResource> L
@inherits BlazoriseCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>
@inherits AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>
<Card>
<CardHeader>
@ -645,15 +645,15 @@ Open the `Books.razor` and replace the content as the following:
> If you see some syntax errors, you can ignore them if your application properly built and run. Visual Studio still has some bugs with Blazor.
* Inherited from the `BlazoriseCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>` which implements all the CRUD details for us.
* Inherited from the `AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>` which implements all the CRUD details for us.
* `Entities`, `TotalCount`, `PageSize`, `OnDataGridReadAsync` are defined in the base blass.
* Injected `IStringLocalizer<BookStoreResource>` (as `L` object) and used for localization.
While the code above pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better.
#### About the BlazoriseCrudPageBase
#### About the AbpCrudPageBase
We will continue to benefit from the `BlazoriseCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications.
We will continue to benefit from the `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications.
## Run the Final Application

20
docs/en/Tutorials/Part-3.md

@ -1163,7 +1163,7 @@ Clicking the "Delete" action calls the `delete` method which then shows a confir
## Creating a New Book
In this section, you will learn how to create a new modal dialog form to create a new book. Since we've inherited from the `BlazoriseCrudPage`, we only need to develop the view part.
In this section, you will learn how to create a new modal dialog form to create a new book. Since we've inherited from the `AbpCrudPageBase`, we only need to develop the view part.
### Add "New Button" Button
@ -1328,7 +1328,7 @@ We can now define a modal to edit the book. Add the following code to the end of
### AutoMapper Configuration
The base `BlazoriseCrudPage` uses the [object to object mapping](../Object-To-Object-Mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
The base `AbpCrudPageBase` uses the [object to object mapping](../Object-To-Object-Mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
Open the `BookStoreBlazorAutoMapperProfile` inside the `Acme.BookStore.Blazor` project and change the content as the following:
@ -1382,7 +1382,7 @@ Here the complete code to create the book management CRUD page, that has been de
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<BookStoreResource> L
@inherits BlazoriseCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>
@inherits AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>
<Card>
<CardHeader>
@ -1392,8 +1392,10 @@ Here the complete code to create the book management CRUD page, that has been de
</Column>
<Column ColumnSize="ColumnSize.Is6">
<Paragraph Alignment="TextAlignment.Right">
<Button Color="Color.Primary"
Clicked="OpenCreateModalAsync">@L["NewBook"]</Button>
<Button Color="Color.Primary"
Clicked="OpenCreateModalAsync">
@L["NewBook"]
</Button>
</Paragraph>
</Column>
</Row>
@ -1406,10 +1408,10 @@ Here the complete code to create the book management CRUD page, that has been de
ShowPager="true"
PageSize="PageSize">
<DataGridColumns>
<DataGridColumn Width="150px"
<DataGridColumn Width="150px"
TItem="BookDto"
Field="@nameof(BookDto.Id)"
Sortable="false"
Field="@nameof(BookDto.Id)"
Sortable="false"
Caption="@L["Actions"]">
<DisplayTemplate>
<Dropdown>
@ -1434,7 +1436,7 @@ Here the complete code to create the book management CRUD page, that has been de
Field="@nameof(BookDto.Type)"
Caption="@L["Type"]">
<DisplayTemplate>
@L[$"Enum:BookType:{(int) context.Type}"]
@L[$"Enum:BookType:{(int)context.Type}"]
</DisplayTemplate>
</DataGridColumn>
<DataGridColumn TItem="BookDto"

3
docs/en/Tutorials/Part-4.md

@ -75,9 +75,12 @@ If you had created a data seed contributor as described in the [first part](Part
Add a new test class, named `BookAppService_Tests` in the `Books` namespace (folder) of the `Acme.BookStore.Application.Tests` project:
````csharp
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books

8
docs/en/Tutorials/Part-5.md

@ -460,7 +460,7 @@ Open the `/src/app/book/book.component.html` file and replace the edit and delet
### Authorize the Razor Component
Open the `/Pages/Books.razor` file in the `Acme.BookStore.Blazor` project and add an `Authorize` attribute just after the `@page` directive, as shown below:
Open the `/Pages/Books.razor` file in the `Acme.BookStore.Blazor` project and add an `Authorize` attribute just after the `@page` directive and the following namespace imports (`@using` lines), as shown below:
````html
@page "/books"
@ -518,7 +518,9 @@ Wrap the *New Book* button by an `if` block as shown below:
@if (canCreateBook)
{
<Button Color="Color.Primary"
Clicked="OpenCreateModalAsync">@L["NewBook"]</Button>
Clicked="OpenCreateModalAsync">
@L["NewBook"]
</Button>
}
````
@ -545,7 +547,7 @@ As similar to the *New Book* button, we can use `if` blocks to conditionally sho
You can run and test the permissions. Remove a book related permission from the admin role to see the related button/action disappears from the UI.
However, ABP Framework caches the permissions of the current user in the client side. So, when you change a permission for yourself, you need to manually **refresh the page** to take the effect. If you don't refresh and try to use the prohibited action you get an HTTP 403 (forbidden) response from the server.
**ABP Framework caches the permissions** of the current user in the client side. So, when you change a permission for yourself, you need to manually **refresh the page** to take the effect. If you don't refresh and try to use the prohibited action you get an HTTP 403 (forbidden) response from the server.
> Changing a permission for a role or user immediately available on the server side. So, this cache system doesn't cause any security problem.

4
docs/en/Tutorials/Part-7.md

@ -74,6 +74,10 @@ Open the **Package Manager Console** on Visual Studio and ensure that the **Defa
Run the following command to create a new database migration:
````bash
Add-Migration "Added_Authors"
````
![bookstore-add-migration-authors](images/bookstore-add-migration-authors.png)
This will create a new migration class. Then run the `Update-Database` command to create the table on the database.

14
docs/en/Tutorials/Part-9.md

@ -1177,6 +1177,20 @@ We should complete the localizations we've used above. Open the `en.json` file u
"NewAuthor": "New author"
````
### Run the Application
Run and login to the application. **If you don't see the Authors menu item under the Book Store menu, that means you don't have the permission yet.** Go to the `identity/roles` page, click to the *Actions* button and select the *Permissions* action for the **admin role**:
![bookstore-author-permissions](images/bookstore-author-permissions.png)
As you see, the admin role has no *Author Management* permissions yet. Click to the checkboxes and save the modal to grant the necessary permissions. You will see the *Authors* menu item under the *Book Store* in the main menu, after **refreshing the page**:
![bookstore-authors-page](images/bookstore-authors-blazor-ui.png)
That's all! This is a fully working CRUD page, you can create, edit and delete the authors.
> **Tip**: If you run the `.DbMigrator` console application after defining a new permission, it automatically grants these new permissions to the admin role and you don't need to manually grant the permissions yourself.
{{end}}
## The Next Part

BIN
docs/en/Tutorials/images/bookstore-authors-blazor-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

24
docs/en/UI/AspNetCore/JavaScript-API/Auth.md

@ -0,0 +1,24 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Auth API
Auth API allows you to check permissions (policies) for the current user in the client side. In this way, you can conditionally show/hide UI parts or perform your client side logic based on the current permissions.
> This document only explains the JavaScript API. See the [authorization document](../../../Authorization.md) to understand the ABP authorization & permission system.
## Basic Usage
`abp.auth.isGranted(...)` function is used to check if a permission/policy has granted or not:
````js
if (abp.auth.isGranted('DeleteUsers')) {
//TODO: Delete the user
} else {
alert("You don't have permission to delete a user!");
}
````
## Other Fields & Functions
* ` abp.auth.isAnyGranted(...)`: Gets one or more permission/policy names and returns `true` if at least one of them has granted.
* `abp.auth.areAllGranted(...)`: Gets one or more permission/policy names and returns `true` if all of them of them have granted.
* `abp.auth.policies`: This is an object where its keys are the permission/policy names. You can find all permission/policy names here.
* `abp.auth.grantedPolicies`: This is an object where its keys are the permission/policy names. You can find the granted permission/policy names here.

56
docs/en/UI/AspNetCore/JavaScript-API/Block-Busy.md

@ -0,0 +1,56 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript UI Block/Busy API
UI Block API disables (blocks) the page or a part of the page.
## Basic Usage
**Example: Block (disable) the complete page**
````js
abp.ui.block();
````
**Example: Block (disable) an HTML element**
````js
abp.ui.block('#MyContainer');
````
**Example: Enables the previously blocked element or page:**
````js
abp.ui.unblock();
````
## Options
`abp.ui.block()` method can get an options object which may contain the following fields:
* `elm`: An optional selector to find the element to be blocked (e.g. `#MyContainerId`). If not provided, the entire page is blocked. The selector can also be directly passed to the `block()` method as shown above.
* `busy`: Set to `true` to show a progress indicator on the blocked area.
* `promise`: A promise object with `always` or `finally` callbacks. This can be helpful if you want to automatically unblock the blocked area when a deferred operation completes.
**Example: Block an element with busy indicator**
````js
abp.ui.block({
elm: '#MySection',
busy: true
});
````
The resulting UI will look like below:
![ui-busy](../../../images/ui-busy.png)
## setBusy
`abp.ui.setBusy(...)` and `abp.ui.clearBusy()` are shortcut functions if you want to use the block with `busy` option.
**Example: Block with busy**
````js
abp.ui.setBusy('#MySection');
````
Then you can use `abp.ui.clearBusy();` to re-enable the busy area/page.

49
docs/en/UI/AspNetCore/JavaScript-API/CurrentUser.md

@ -0,0 +1,49 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript CurrentUser API
`abp.currentUser` is an object that contains information about the current user of the application.
> This document only explains the JavaScript API. See the [CurrentUser document](../../../CurrentUser.md) to get information about the current user in the server side.
## Authenticated User
If the user was authenticated, this object will be something like below:
````js
{
isAuthenticated: true,
id: "34f1f4a7-13cc-4b91-84d1-b91c87afa95f",
tenantId: null,
userName: "john",
name: "John",
surName: "Nash",
email: "john.nash@abp.io",
emailVerified: true,
phoneNumber: null,
phoneNumberVerified: false,
roles: ["moderator","supporter"]
}
````
So, `abp.currentUser.userName` returns `john` in this case.
## Anonymous User
If the user was not authenticated, this object will be something like below:
````js
{
isAuthenticated: false,
id: null,
tenantId: null,
userName: null,
name: null,
surName: null,
email: null,
emailVerified: false,
phoneNumber: null,
phoneNumberVerified: false,
roles: []
}
````
You can check `abp.currentUser.isAuthenticated` to understand if the use was authenticated or not.

117
docs/en/UI/AspNetCore/JavaScript-API/DOM.md

@ -0,0 +1,117 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript DOM API
`abp.dom` (Document Object Model) provides events that you can subscribe to get notified when elements dynamically added to and removed from the page (DOM).
It is especially helpful if you want to initialize the new loaded elements. This is generally needed when you dynamically add elements to DOM (for example, get some HTML elements via AJAX) after page initialization.
> ABP uses the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to observe the changes made on the DOM.
## Node Events
### onNodeAdded
This event is triggered when an element is added to the DOM. Example:
````js
abp.dom.onNodeAdded(function(args){
console.log(args.$el);
});
````
`args` object has the following fields;
* `$el`: The JQuery selection to get the new element inserted to the DOM.
### onNodeRemoved
This event is triggered when an element is removed from the DOM. Example:
````js
abp.dom.onNodeRemoved(function(args){
console.log(args.$el);
});
````
`args` object has the following fields;
* `$el`: The JQuery selection to get the element removed from the DOM.
## Pre-Build Initializers
ABP Framework is using the DOM events to initialize some kind of HTML elements when they are added to the DOM after than the page was already initialized.
> Note that the same initializers also work if these elements were already included in the initial DOM. So, whether they are initially or lazy loaded, they work as expected.
### Form Initializer
The Form initializer (defined as `abp.dom.initializers.initializeForms`) initializes the lazy loaded forms;
* Automatically enabled the `unobtrusive` validation on the form.
* Can automatically show a confirmation message when you submit the form. To enable this feature, just add `data-confirm` attribute with a message (like `data-confirm="Are you sure?"`) to the `form` element.
* If the `form` element has `data-ajaxForm="true"` attribute, then automatically calls the `.abpAjaxForm()` on the `form` element, to make the form posted via AJAX.
See the [Forms & Validation](../Forms-Validation.md) document for more.
### Script Initializer
Script initializer (`abp.dom.initializers.initializeScript`) can execute a JavaScript code for a DOM element.
**Example: Lazy load a component and execute some code when the element has loaded**
Assume that you've a container to load the element inside:
````html
<div id="LazyComponent"></div>
````
And this is the component that will be loaded via AJAX from the server and inserted into the container:
````html
<div data-script-class="MyCustomClass">
<p>Sample message</p>
</div>
````
`data-script-class="MyCustomClass"` indicates the JavaScript class that will be used to perform some logic on this element:
`MyCustomClass` is a global object defined as shown below:
````js
MyCustomClass = function(){
function initDom($el){
$el.css('color', 'red');
}
return {
initDom: initDom
}
};
````
`initDom` is the function that is called by the ABP Framework. The `$el` argument is the loaded HTML element as a JQuery selection.
Finally, you can load the component inside the container after an AJAX call:
````js
$(function () {
setTimeout(function(){
$.get('/get-my-element').then(function(response){
$('#LazyComponent').html(response);
});
}, 2000);
});
````
Script Initialization system is especially helpful if you don't know how and when the component will be loaded into the DOM. This can be possible if you've developed a reusable UI component in a library and you want the application developer shouldn't care how to initialize the component in different use cases.
> Script initialization doesn't work if the component was loaded in the initial DOM. In this case, you are responsible to initialize it.
### Other Initializers
The following Bootstrap components and libraries are automatically initialized when they are added to the DOM:
* Tooltip
* Popover
* Timeage

15
docs/en/UI/AspNetCore/JavaScript-API/Features.md

@ -0,0 +1,15 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Features API
`abp.features` API allows you to check features or get the values of the features on the client side. You can read the current value of a feature in the client side only if it is allowed by the feature definition (on the server side).
> This document only explains the JavaScript API. See the [Features](../../../Features.md) document to understand the ABP Features system.
## Basic Usage
`abp.features.values` can be used to access to the all feature values.
````js
var excelExportFeatureValue = abp.features.values["ExportingToExcel"];
````
Then you can check the value of the feature to perform your logic.

28
docs/en/UI/AspNetCore/JavaScript-API/Index.md

@ -4,18 +4,16 @@ ABP provides a set of JavaScript APIs for ASP.NET Core MVC / Razor Pages applica
## APIs
* [abp.ajax](Ajax.md)
* abp.auth
* abp.currentUser
* abp.dom
* [abp.event](Events.md)
* abp.features
* [abp.localization](Localization.md)
* abp.log
* [abp.message](Message.md)
* [abp.notify](Notify.md)
* abp.security
* [abp.setting](Settings.md)
* abp.ui
* abp.utils
* abp.ResourceLoader
* [AJAX](Ajax.md)
* [Auth](Auth.md)
* [CurrentUser](CurrentUser.md)
* [DOM](DOM.md)
* [Events](Events.md)
* [Features](Features.md)
* [Localization](Localization.md)
* [Logging](Logging.md)
* [ResourceLoader](ResourceLoader.md)
* [Settings](Settings.md)
* [UI Block/Busy](Block-Busy.md)
* [UI Message](Message.md)
* [UI Notification](Notify.md)

49
docs/en/UI/AspNetCore/JavaScript-API/Logging.md

@ -1,3 +1,50 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Logging API
TODO
`abp.log` API is used to write simple logs in the client side.
> The logs are written to console, using the `console.log`, by default.
> This document is for simple client side logging. See the [Logging](../../../Logging.md) document for server side logging system.
## Basic Usage
Use one of the `abp.log.xxx(...)` methods based on the severity of your log message.
````js
abp.log.debug("Some debug log here..."); //Logging a simple debug message
abp.log.info({ name: "john", age: 42 }); //Logging an object as an information log
abp.log.warn("A warning message"); //Logging a warning message
abp.log.error('An error happens...'); //Error message
abp.log.fatal('Network connection has gone away!'); //Fatal error
````
## Log Levels
There are 5 levels for a log message:
* DEBUG = 1
* INFO = 2
* WARN = 3
* ERROR = 4
* FATAL = 5
These are defined in the `abp.log.levels` object (like `abp.log.levels.WARN`).
### Changing the Current Log Level
You can control the log level as shown below:
````js
abp.log.level = abp.log.levels.WARN;
````
Default log level is `DEBUG`.
### Logging with Specifying the Level
Instead of calling `abp.log.info(...)` function, you can use the `abp.log.log` by specifying the log level as a parameter:
````js
abp.log.log("log message...", abp.log.levels.INFO);
````

40
docs/en/UI/AspNetCore/JavaScript-API/ResourceLoader.md

@ -0,0 +1,40 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Resource Loader API
`abp.ResourceLoader` is a service that can load a JavaScript or CSS file on demand. It guarantees to load the file only once even if you request multiple times.
## Loading Script Files
`abp.ResourceLoader.loadScript(...)` function **loads** a JavaScript file from the server and **executes** it.
**Example: Load a JavaScript file**
````js
abp.ResourceLoader.loadScript('/Pages/my-script.js');
````
### Parameters
`loadScript` function can get three parameters;
* `url` (required, `string`): The URL of the script file to be loaded.
* `loadCallback` (optional, `function`): A callback function that is called once the script is loaded & executed. In this callback you can safely use the code in the script file. This callback is called even if the file was loaded before.
* `failCallback` (optional, `function`): A callback function that is called if loading the script fails.
**Example: Provide the `loadCallback` argument**
````js
abp.ResourceLoader.loadScript('/Pages/my-script.js', function() {
console.log('successfully loaded :)');
});
````
## Loading Style Files
`abp.ResourceLoader.loadStyle(...)` function adds a `link` element to the `head` of the document for the given URL, so the CSS file is automatically loaded by the browser.
**Example: Load a CSS file**
````js
abp.ResourceLoader.loadStyle('/Pages/my-styles.css');
````

28
docs/en/docs-nav.json

@ -463,10 +463,22 @@
"text": "Localization",
"path": "UI/AspNetCore/JavaScript-API/Localization.md"
},
{
"text": "Auth",
"path": "UI/AspNetCore/JavaScript-API/Auth.md"
},
{
"text": "Current User",
"path": "UI/AspNetCore/JavaScript-API/CurrentUser.md"
},
{
"text": "Settings",
"path": "UI/AspNetCore/JavaScript-API/Settings.md"
},
{
"text": "Features",
"path": "UI/AspNetCore/JavaScript-API/Features.md"
},
{
"text": "AJAX",
"path": "UI/AspNetCore/JavaScript-API/Ajax.md"
@ -479,9 +491,25 @@
"text": "Notify",
"path": "UI/AspNetCore/JavaScript-API/Notify.md"
},
{
"text": "Block/Busy",
"path": "UI/AspNetCore/JavaScript-API/Block-Busy.md"
},
{
"text": "Events",
"path": "UI/AspNetCore/JavaScript-API/Events.md"
},
{
"text": "DOM",
"path": "UI/AspNetCore/JavaScript-API/DOM.md"
},
{
"text": "Logging",
"path": "UI/AspNetCore/JavaScript-API/Logging.md"
},
{
"text": "Resource Loader",
"path": "UI/AspNetCore/JavaScript-API/ResourceLoader.md"
}
]
},

BIN
docs/en/images/ui-busy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

8
framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs

@ -1,9 +1,13 @@
namespace Volo.Abp.Settings
using System.Collections.Generic;
namespace Volo.Abp.Settings
{
public interface ISettingDefinitionContext
{
SettingDefinition GetOrNull(string name);
IReadOnlyList<SettingDefinition> GetAll();
void Add(params SettingDefinition[] definitions);
}
}
}

9
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs

@ -76,9 +76,9 @@ namespace Volo.Abp.Account.Web.Pages.Account
EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);
if (context?.ClientId != null)
if (context?.Client?.ClientId != null)
{
var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId);
var client = await ClientStore.FindEnabledClientByIdAsync(context?.Client?.ClientId);
if (client != null)
{
EnableLocalLogin = client.EnableLocalLogin;
@ -108,7 +108,10 @@ namespace Volo.Abp.Account.Web.Pages.Account
return Redirect("~/");
}
await Interaction.GrantConsentAsync(context, ConsentResponse.Denied);
await Interaction.GrantConsentAsync(context, new ConsentResponse()
{
Error = AuthorizationError.AccessDenied
});
return Redirect(ReturnUrl);
}

6
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml

@ -96,8 +96,8 @@
}
<div>
<button name="UserDecision" value="yes" class="btn btn-primary" autofocus>Yes, Allow</button>
<button name="UserDecision" value="no" class="btn">No, Do Not Allow</button>
<button name="ConsentInput.UserDecision" value="yes" class="btn btn-primary" autofocus>Yes, Allow</button>
<button name="ConsentInput.UserDecision" value="no" class="btn">No, Do Not Allow</button>
@if (Model.ClientInfo.ClientUrl != null)
{
<a class="pull-right btn btn-secondary" target="_blank" href="@Model.ClientInfo.ClientUrl">
@ -110,4 +110,4 @@
</form>
</abp-card-body>
</abp-card>
</abp-card>

56
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Abp.UI;
@ -50,16 +51,16 @@ namespace Volo.Abp.Account.Web.Pages
throw new ApplicationException($"No consent request matching request: {ReturnUrl}");
}
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
var client = await _clientStore.FindEnabledClientByIdAsync(request.Client.ClientId);
if (client == null)
{
throw new ApplicationException($"Invalid client id: {request.ClientId}");
throw new ApplicationException($"Invalid client id: {request.Client.ClientId}");
}
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ValidatedResources.RawScopeValues);
if (resources == null || (!resources.IdentityResources.Any() && !resources.ApiResources.Any()))
{
throw new ApplicationException($"No scopes matching: {request.ScopesRequested.Aggregate((x, y) => x + ", " + y)}");
throw new ApplicationException($"No scopes matching: {request.ValidatedResources.RawScopeValues.Aggregate((x, y) => x + ", " + y)}");
}
ClientInfo = new ClientInfoModel(client);
@ -67,14 +68,26 @@ namespace Volo.Abp.Account.Web.Pages
{
RememberConsent = true,
IdentityScopes = resources.IdentityResources.Select(x => CreateScopeViewModel(x, true)).ToList(),
ApiScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => CreateScopeViewModel(x, true)).ToList()
};
var apiScopes = new List<ScopeViewModel>();
foreach(var parsedScope in request.ValidatedResources.ParsedScopes)
{
var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName);
if (apiScope != null)
{
var scopeVm = CreateScopeViewModel(parsedScope, apiScope, true);
apiScopes.Add(scopeVm);
}
}
if (resources.OfflineAccess)
{
ConsentInput.ApiScopes.Add(GetOfflineAccessScope(true));
apiScopes.Add(GetOfflineAccessScope(true));
}
ConsentInput.ApiScopes = apiScopes;
return Page();
}
@ -104,7 +117,10 @@ namespace Volo.Abp.Account.Web.Pages
if (ConsentInput.UserDecision == "no")
{
grantedConsent = ConsentResponse.Denied;
grantedConsent = new ConsentResponse
{
Error = AuthorizationError.AccessDenied
};
}
else
{
@ -113,7 +129,7 @@ namespace Volo.Abp.Account.Web.Pages
grantedConsent = new ConsentResponse
{
RememberConsent = ConsentInput.RememberConsent,
ScopesConsented = ConsentInput.GetAllowedScopeNames()
ScopesValuesConsented = ConsentInput.GetAllowedScopeNames()
};
}
else
@ -151,16 +167,22 @@ namespace Volo.Abp.Account.Web.Pages
};
}
protected virtual ConsentModel.ScopeViewModel CreateScopeViewModel(Scope scope, bool check)
protected virtual ConsentModel.ScopeViewModel CreateScopeViewModel(ParsedScopeValue parsedScopeValue, ApiScope apiScope, bool check)
{
return new ConsentModel.ScopeViewModel
var displayName = apiScope.DisplayName ?? apiScope.Name;
if (!string.IsNullOrWhiteSpace(parsedScopeValue.ParsedParameter))
{
displayName += ":" + parsedScopeValue.ParsedParameter;
}
return new ScopeViewModel
{
Name = scope.Name,
DisplayName = scope.DisplayName,
Description = scope.Description,
Emphasize = scope.Emphasize,
Required = scope.Required,
Checked = check || scope.Required
Name = parsedScopeValue.RawValue,
DisplayName = displayName,
Description = apiScope.Description,
Emphasize = apiScope.Emphasize,
Required = apiScope.Required,
Checked = check || apiScope.Required
};
}
@ -241,4 +263,4 @@ namespace Volo.Abp.Account.Web.Pages
}
}
}
}
}

2
modules/cms-kit/host/Volo.CmsKit.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs

@ -142,7 +142,7 @@ namespace Volo.CmsKit.IdentityServer
string postLogoutRedirectUri = null,
IEnumerable<string> permissions = null)
{
var client = await _clientRepository.FindByCliendIdAsync(name);
var client = await _clientRepository.FindByClientIdAsync(name);
if (client == null)
{
client = await _clientRepository.InsertAsync(

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs

@ -114,7 +114,7 @@ namespace Volo.Abp.FeatureManagement
policyName = Options.ProviderPolicies.GetOrDefault(providerName);
if (policyName.IsNullOrEmpty())
{
throw new AbpException($"No policy defined to get/set permissions for the provider '{policyName}'. Use {nameof(FeatureManagementOptions)} to map the policy.");
throw new AbpException($"No policy defined to get/set permissions for the provider '{providerName}'. Use {nameof(FeatureManagementOptions)} to map the policy.");
}
}

27
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs

@ -32,16 +32,22 @@ namespace Volo.Abp.Identity
return;
}
var userLink = new IdentityLinkUser(
GuidGenerator.Create(),
sourceLinkUser,
targetLinkUser);
await IdentityLinkUserRepository.InsertAsync(userLink, true);
using (CurrentTenant.Change(null))
{
var userLink = new IdentityLinkUser(
GuidGenerator.Create(),
sourceLinkUser,
targetLinkUser);
await IdentityLinkUserRepository.InsertAsync(userLink, true);
}
}
public virtual async Task<bool> IsLinkedAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
{
return await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser) != null;
using (CurrentTenant.Change(null))
{
return await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser) != null;
}
}
public virtual async Task UnlinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
@ -51,10 +57,13 @@ namespace Volo.Abp.Identity
return;
}
var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser);
if (linkedUser != null)
using (CurrentTenant.Change(null))
{
await IdentityLinkUserRepository.DeleteAsync(linkedUser);
var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser);
if (linkedUser != null)
{
await IdentityLinkUserRepository.DeleteAsync(linkedUser);
}
}
}

12
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceConsts.cs

@ -2,8 +2,12 @@
{
public class ApiResourceConsts
{
public const int NameMaxLength = 200;
public const int DisplayNameMaxLength = 200;
public const int DescriptionMaxLength = 1000;
public static int NameMaxLength { get; set; } = 200;
public static int DisplayNameMaxLength { get; set; } = 200;
public static int DescriptionMaxLength { get; set; } = 1000;
public static int AllowedAccessTokenSigningAlgorithmsMaxLength { get; set; } = 100;
}
}
}

2
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceEto.cs

@ -17,4 +17,4 @@ namespace Volo.Abp.IdentityServer.ApiResources
public bool Enabled { get; set; }
}
}
}

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourcePropertyConsts.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiResourcePropertyConsts
{
public static int KeyMaxLength { get; set; } = 250;
public static int ValueMaxLength { get; set; } = 2000;
}
}

7
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceScopeConsts.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiResourceScopeConsts
{
public static int ScopeMaxLength { get; set; } = 200;
}
}

20
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiResourceSecretConsts.cs

@ -0,0 +1,20 @@
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiResourceSecretConsts
{
/// <summary>
/// Default value: 250
/// </summary>
public static int TypeMaxLength { get; set; } = 250;
/// <summary>
/// Default value: 4000
/// </summary>
public static int ValueMaxLength { get; set; } = 4000;
/// <summary>
/// Default value: 1000
/// </summary>
public static int DescriptionMaxLength { get; set; } = 1000;
}
}

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiResources/ApiScopeConsts.cs

@ -1,9 +0,0 @@
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiScopeConsts
{
public const int NameMaxLength = 200;
public const int DisplayNameMaxLength = 200;
public const int DescriptionMaxLength = 1000;
}
}

11
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiResourceConsts.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScopeConsts
{
public static int NameMaxLength { get; set; } = 200;
public static int DisplayNameMaxLength { get; set; } = 200;
public static int DescriptionMaxLength { get; set; } = 1000;
}
}

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiScopePropertyConsts.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScopePropertyConsts
{
public static int KeyMaxLength { get; set; } = 250;
public static int ValueMaxLength { get; set; } = 2000;
}
}

7
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientClaimConsts.cs

@ -2,7 +2,8 @@
{
public class ClientClaimConsts
{
public const int TypeMaxLength = 250;
public const int ValueMaxLength = 250;
public static int TypeMaxLength { get; set; } = 250;
public static int ValueMaxLength { get; set; } = 250;
}
}
}

26
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientConsts.cs

@ -2,26 +2,28 @@
{
public class ClientConsts
{
public const int ClientIdMaxLength = 200;
public static int ClientIdMaxLength { get; set; } = 200;
public const int ProtocolTypeMaxLength = 200;
public static int ProtocolTypeMaxLength { get; set; } = 200;
public const int ClientNameMaxLength = 200;
public static int ClientNameMaxLength { get; set; } = 200;
public const int ClientUriMaxLength = 2000;
public static int ClientUriMaxLength { get; set; } = 2000;
public const int LogoUriMaxLength = 2000;
public static int LogoUriMaxLength { get; set; } = 2000;
public const int DescriptionMaxLength = 1000;
public static int DescriptionMaxLength { get; set; } = 1000;
public const int FrontChannelLogoutUriMaxLength = 2000;
public static int FrontChannelLogoutUriMaxLength { get; set; } = 2000;
public const int BackChannelLogoutUriMaxLength = 2000;
public static int BackChannelLogoutUriMaxLength { get; set; } = 2000;
public const int ClientClaimsPrefixMaxLength = 200;
public static int ClientClaimsPrefixMaxLength { get; set; } = 200;
public const int PairWiseSubjectSaltMaxLength = 200;
public static int PairWiseSubjectSaltMaxLength { get; set; } = 200;
public const int UserCodeTypeMaxLength = 100;
public static int UserCodeTypeMaxLength { get; set; } = 100;
public static int AllowedIdentityTokenSigningAlgorithms { get; set; } = 100;
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientCorsOriginConsts.cs

@ -2,6 +2,6 @@
{
public class ClientCorsOriginConsts
{
public const int OriginMaxLength = 150;
public static int OriginMaxLength { get; set; } = 150;
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientGrantTypeConsts.cs

@ -2,6 +2,6 @@
{
public class ClientGrantTypeConsts
{
public const int GrantTypeMaxLength = 250;
public static int GrantTypeMaxLength { get; set; } = 250;
}
}
}

12
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/SecretConsts.cs → modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Clients/ClientSecretConsts.cs

@ -1,22 +1,20 @@
namespace Volo.Abp.IdentityServer
namespace Volo.Abp.IdentityServer.Clients
{
public class SecretConsts
public class ClientSecretConsts
{
/// <summary>
/// Default value: 250
/// </summary>
public static int TypeMaxLength { get; set; } = 250;
/// <summary>
/// Default value: 4000
/// </summary>
public static int ValueMaxLength { get; set; } = 4000;
public static int ValueMaxLengthValue { get; set; } = ValueMaxLength;
/// <summary>
/// Default value: 2000
/// </summary>
public static int DescriptionMaxLength { get; set; } = 2000;
}
}
}

19
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesConsts.cs

@ -0,0 +1,19 @@
namespace Volo.Abp.IdentityServer.Devices
{
public class DeviceFlowCodesConsts
{
public static int DeviceCodeMaxLength { get; set; } = 200;
public static int UserCodeMaxLength { get; set; } = 200;
public static int SubjectIdMaxLength { get; set; } = 200;
public static int SessionIdMaxLength { get; set; } = 100;
public static int DescriptionMaxLength { get; set; } = 200;
public static int ClientIdMaxLength { get; set; } = 200;
public static int DataMaxLength { get; set; } = 50000;
}
}

6
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesEto.cs

@ -13,10 +13,14 @@ namespace Volo.Abp.IdentityServer.Devices
public string SubjectId { get; set; }
public string SessionId { get; set; }
public string ClientId { get; set; }
public string Description { get; set; }
public DateTime? Expiration { get; set; }
public string Data { get; set; }
}
}
}

22
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Grants/PersistedGrantConsts.cs

@ -6,30 +6,40 @@
/// Default value: 200
/// </summary>
public static int KeyMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 50
/// </summary>
public static int TypeMaxLength { get; set; } = 50;
/// <summary>
/// Default value: 200
/// </summary>
public static int SubjectIdMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 100
/// </summary>
public static int SessionIdMaxLength { get; set; } = 100;
/// <summary>
/// Default value: 200
/// </summary>
public static int ClientIdMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 200
/// </summary>
public static int DescriptionMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 50000
/// </summary>
public static int DataMaxLength { get; set; } = 50000;
/// <summary>
/// Default value: 50000
/// </summary>
public static int DataMaxLengthValue { get; set; } = 50000;
}
}
}

8
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceConsts.cs

@ -6,15 +6,15 @@
/// Default value: 200
/// </summary>
public static int NameMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 200
/// </summary>
public static int DisplayNameMaxLength { get; set; } = 200;
/// <summary>
/// Default value: 200
/// Default value: 1000
/// </summary>
public static int DescriptionMaxLength { get; set; } = 1000;
}
}
}

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/IdentityResources/IdentityResourcePropertyConsts.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.IdentityServer.IdentityResources
{
public class IdentityResourcePropertyConsts
{
public static int KeyMaxLength { get; set; } = 250;
public static int ValueMaxLength { get; set; } = 2000;
}
}

1
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/en.json

@ -3,6 +3,7 @@
"texts": {
"Volo.IdentityServer:DuplicateIdentityResourceName": "Identity Resource name already exist: {Name}",
"Volo.IdentityServer:DuplicateApiResourceName": "Api Resource name already exist: {Name}",
"Volo.IdentityServer:DuplicateApiScopeName": "Api Scope name already exist: {Name}",
"Volo.IdentityServer:DuplicateClientId": "ClientId already exist: {ClientId}",
"UserLockedOut": "The user account has been locked out due to invalid login attempts. Please wait a while and try again.",
"InvalidUserNameOrPassword": "Invalid username or password!",

1
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/zh-Hans.json

@ -3,6 +3,7 @@
"texts": {
"Volo.IdentityServer:DuplicateIdentityResourceName": "Identity资源名称已存在: {Name}",
"Volo.IdentityServer:DuplicateApiResourceName": "Api资源名称已存在: {Name}",
"Volo.IdentityServer:DuplicateApiScopeName": "Api Scope已存在: {Name}",
"Volo.IdentityServer:DuplicateClientId": "ClientId已经存在: {ClientId}",
"UserLockedOut": "登录失败,用户账户已被锁定.请稍后再试.",
"InvalidUserNameOrPassword": "用户名或密码错误!",

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/ObjectExtending/IdentityServerModuleExtensionConfiguration.cs

@ -23,6 +23,15 @@ namespace Volo.Abp.ObjectExtending
);
}
public IdentityServerModuleExtensionConfiguration ConfigureApiScope(
Action<EntityExtensionConfiguration> configureAction)
{
return this.ConfigureEntity(
IdentityServerModuleExtensionConsts.EntityNames.ApiScope,
configureAction
);
}
public IdentityServerModuleExtensionConfiguration ConfigureIdentityResource(
Action<EntityExtensionConfiguration> configureAction)
{

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/ObjectExtending/IdentityServerModuleExtensionConsts.cs

@ -11,6 +11,8 @@
public const string IdentityResource = "IdentityResource";
public const string ApiResource = "ApiResource";
public const string ApiScope = "ApiScope";
}
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj

@ -25,8 +25,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="IdentityServer4" Version="3.1.3" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="3.1.3" />
<PackageReference Include="IdentityServer4" Version="4.1.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" />
</ItemGroup>
</Project>

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs

@ -55,7 +55,9 @@ namespace Volo.Abp.IdentityServer
return builder;
}
public static IIdentityServerBuilder AddAbpDeveloperSigningCredential(
//TODO: Use the latest Identity server code to optimize performance.
// https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/src/Configuration/DependencyInjection/BuilderExtensions/Crypto.cs
private static IIdentityServerBuilder AddAbpDeveloperSigningCredential(
this IIdentityServerBuilder builder,
bool persistKey = true,
string filename = null,

3
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs

@ -10,6 +10,7 @@ using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.AspNetIdentity;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.IdentityResources;
@ -68,7 +69,7 @@ namespace Volo.Abp.IdentityServer
if (builderOptions.AddDeveloperSigningCredential)
{
identityServerBuilder = identityServerBuilder.AddAbpDeveloperSigningCredential();
identityServerBuilder = identityServerBuilder.AddDeveloperSigningCredential();
}
identityServerBuilder.AddAbpIdentityServer(builderOptions);

37
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedSigningAlgorithmsConverter.cs

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
namespace Volo.Abp.IdentityServer
{
public class AllowedSigningAlgorithmsConverter :
IValueConverter<ICollection<string>, string>,
IValueConverter<string, ICollection<string>>
{
public static AllowedSigningAlgorithmsConverter Converter = new AllowedSigningAlgorithmsConverter();
public string Convert(ICollection<string> sourceMember, ResolutionContext context)
{
if (sourceMember == null || !sourceMember.Any())
{
return null;
}
return sourceMember.Aggregate((x, y) => $"{x},{y}");
}
public ICollection<string> Convert(string sourceMember, ResolutionContext context)
{
var list = new HashSet<string>();
if (!String.IsNullOrWhiteSpace(sourceMember))
{
sourceMember = sourceMember.Trim();
foreach (var item in sourceMember.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct())
{
list.Add(item);
}
}
return list;
}
}
}

72
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResource.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using IdentityServer4;
@ -18,13 +18,17 @@ namespace Volo.Abp.IdentityServer.ApiResources
public virtual bool Enabled { get; set; }
public virtual List<ApiSecret> Secrets { get; protected set; }
public virtual string AllowedAccessTokenSigningAlgorithms { get; set; }
public virtual List<ApiScope> Scopes { get; protected set; }
public virtual bool ShowInDiscoveryDocument { get; set; } = true;
public virtual List<ApiResourceSecret> Secrets { get; protected set; }
public virtual List<ApiResourceScope> Scopes { get; protected set; }
public virtual List<ApiResourceClaim> UserClaims { get; protected set; }
public virtual Dictionary<string, string> Properties { get; protected set; }
public virtual List<ApiResourceProperty> Properties { get; protected set; }
protected ApiResource()
{
@ -44,21 +48,21 @@ namespace Volo.Abp.IdentityServer.ApiResources
Enabled = true;
Secrets = new List<ApiSecret>();
Scopes = new List<ApiScope>();
Secrets = new List<ApiResourceSecret>();
Scopes = new List<ApiResourceScope>();
UserClaims = new List<ApiResourceClaim>();
Properties = new Dictionary<string, string>();
Properties = new List<ApiResourceProperty>();
Scopes.Add(new ApiScope(id, name, displayName, description));
Scopes.Add(new ApiResourceScope(id, name));
}
public virtual void AddSecret(
[NotNull] string value,
[NotNull] string value,
DateTime? expiration = null,
string type = IdentityServerConstants.SecretTypes.SharedSecret,
string description = null)
{
Secrets.Add(new ApiSecret(Id, value, expiration, type, description));
Secrets.Add(new ApiResourceSecret(Id, value, expiration, type, description));
}
public virtual void RemoveSecret([NotNull] string value, string type = IdentityServerConstants.SecretTypes.SharedSecret)
@ -66,22 +70,16 @@ namespace Volo.Abp.IdentityServer.ApiResources
Secrets.RemoveAll(s => s.Value == value && s.Type == type);
}
public virtual ApiSecret FindSecret([NotNull] string value, string type = IdentityServerConstants.SecretTypes.SharedSecret)
public virtual ApiResourceSecret FindSecret([NotNull] string value, string type = IdentityServerConstants.SecretTypes.SharedSecret)
{
return Secrets.FirstOrDefault(s => s.Type == type && s.Value == value);
}
public virtual ApiScope AddScope(
[NotNull] string name,
string displayName = null,
string description = null,
bool required = false,
bool emphasize = false,
bool showInDiscoveryDocument = true)
public virtual ApiResourceScope AddScope([NotNull] string scope)
{
var scope = new ApiScope(Id, name, displayName, description, required, emphasize, showInDiscoveryDocument);
Scopes.Add(scope);
return scope;
var apiResourceScope = new ApiResourceScope(Id, scope);
Scopes.Add(apiResourceScope);
return apiResourceScope;
}
public virtual void AddUserClaim([NotNull] string type)
@ -111,21 +109,37 @@ namespace Volo.Abp.IdentityServer.ApiResources
public virtual void RemoveAllScopes()
{
foreach (var scope in Scopes)
{
scope.RemoveAllUserClaims();
}
Scopes.Clear();
}
public virtual void RemoveScope(string name)
public virtual void RemoveScope(string scope)
{
Scopes.RemoveAll(r => r.Scope == scope);
}
public virtual ApiResourceScope FindScope(string scope)
{
return Scopes.FirstOrDefault(r => r.Scope == scope);
}
public virtual void AddProperty([NotNull] string key, string value)
{
Properties.Add(new ApiResourceProperty(Id, key, value));
}
public virtual void RemoveAllProperties()
{
Properties.Clear();
}
public virtual void RemoveProperty(string key)
{
Scopes.RemoveAll(r => r.Name == name);
Properties.RemoveAll(r => r.Key == key);
}
public virtual ApiScope FindScope(string name)
public virtual ApiResourceProperty FindProperty(string key)
{
return Scopes.FirstOrDefault(r => r.Name == name);
return Properties.FirstOrDefault(r => r.Key == key);
}
}
}

2
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceClaim.cs

@ -28,4 +28,4 @@ namespace Volo.Abp.IdentityServer.ApiResources
return new object[] {ApiResourceId, Type};
}
}
}
}

39
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceProperty.cs

@ -0,0 +1,39 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiResourceProperty : Entity
{
public virtual Guid ApiResourceId { get; protected set; }
public virtual string Key { get; set; }
public virtual string Value { get; set; }
protected ApiResourceProperty()
{
}
public virtual bool Equals(Guid aiResourceId, [NotNull] string key, string value)
{
return ApiResourceId == aiResourceId && Key == key && Value == value;
}
protected internal ApiResourceProperty(Guid aiResourceId, [NotNull] string key, [NotNull] string value)
{
Check.NotNull(key, nameof(key));
ApiResourceId = aiResourceId;
Key = key;
Value = value;
}
public override object[] GetKeys()
{
return new object[] { ApiResourceId, Key };
}
}
}

38
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceScope.cs

@ -0,0 +1,38 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiResourceScope : Entity
{
public virtual Guid ApiResourceId { get; protected set; }
public virtual string Scope { get; set; }
protected ApiResourceScope()
{
}
public virtual bool Equals(Guid apiResourceId, [NotNull] string scope)
{
return ApiResourceId == apiResourceId && Scope == scope;
}
protected internal ApiResourceScope(
Guid apiResourceId,
[NotNull] string scope)
{
Check.NotNull(scope, nameof(scope));
ApiResourceId = apiResourceId;
Scope = scope;
}
public override object[] GetKeys()
{
return new object[] { ApiResourceId, Scope };
}
}
}

20
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiSecret.cs → modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResourceSecret.cs

@ -4,11 +4,11 @@ using JetBrains.Annotations;
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiSecret : Secret
public class ApiResourceSecret : Secret
{
public virtual Guid ApiResourceId { get; protected set; }
protected ApiSecret()
protected ApiResourceSecret()
{
}
@ -18,16 +18,16 @@ namespace Volo.Abp.IdentityServer.ApiResources
return ApiResourceId == apiResourceId && Value == value && Type == type;
}
protected internal ApiSecret(
protected internal ApiResourceSecret(
Guid apiResourceId,
[NotNull] string value,
DateTime? expiration = null,
string type = IdentityServerConstants.SecretTypes.SharedSecret,
[NotNull] string value,
DateTime? expiration = null,
string type = IdentityServerConstants.SecretTypes.SharedSecret,
string description = null
) : base(
value,
expiration,
type,
value,
expiration,
type,
description)
{
ApiResourceId = apiResourceId;
@ -38,4 +38,4 @@ namespace Volo.Abp.IdentityServer.ApiResources
return new object[] { ApiResourceId, Type, Value };
}
}
}
}

37
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiScopeClaim.cs

@ -1,37 +0,0 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.IdentityServer.ApiResources
{
public class ApiScopeClaim : UserClaim
{
public Guid ApiResourceId { get; protected set; }
[NotNull]
public string Name { get; protected set; }
protected ApiScopeClaim()
{
}
public virtual bool Equals(Guid apiResourceId, [NotNull] string name, [NotNull] string type)
{
return ApiResourceId == apiResourceId && Name == name && Type == type;
}
protected internal ApiScopeClaim(Guid apiResourceId, [NotNull] string name, [NotNull] string type)
: base(type)
{
Check.NotNull(name, nameof(name));
ApiResourceId = apiResourceId;
Name = name;
}
public override object[] GetKeys()
{
return new object[] { ApiResourceId, Name, Type };
}
}
}

15
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/IApiResourceRepository.cs

@ -9,7 +9,13 @@ namespace Volo.Abp.IdentityServer.ApiResources
public interface IApiResourceRepository : IBasicRepository<ApiResource, Guid>
{
Task<ApiResource> FindByNameAsync(
string name,
string apiResourceName,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
Task<List<ApiResource>> FindByNameAsync(
string[] apiResourceNames,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
@ -29,15 +35,10 @@ namespace Volo.Abp.IdentityServer.ApiResources
CancellationToken cancellationToken = default
);
Task<List<ApiResource>> GetListAsync(
bool includeDetails = false,
CancellationToken cancellationToken = default
);
Task<bool> CheckNameExistAsync(
string name,
Guid? expectedId = null,
CancellationToken cancellationToken = default
);
}
}
}

63
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiScope.cs → modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScope.cs

@ -1,14 +1,14 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace Volo.Abp.IdentityServer.ApiResources
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScope : Entity
public class ApiScope : FullAuditedAggregateRoot<Guid>
{
public virtual Guid ApiResourceId { get; protected set; }
public virtual bool Enabled { get; set; }
[NotNull]
public virtual string Name { get; protected set; }
@ -25,41 +25,41 @@ namespace Volo.Abp.IdentityServer.ApiResources
public virtual List<ApiScopeClaim> UserClaims { get; protected set; }
public virtual List<ApiScopeProperty> Properties { get; protected set; }
protected ApiScope()
{
}
public virtual bool Equals(Guid apiResourceId, [NotNull] string name)
{
return ApiResourceId == apiResourceId && Name == name;
}
protected internal ApiScope(
Guid apiResourceId,
[NotNull] string name,
string displayName = null,
string description = null,
bool required = false,
bool emphasize = false,
bool showInDiscoveryDocument = true)
public ApiScope(
Guid id,
[NotNull] string name,
string displayName = null,
string description = null,
bool required = false,
bool emphasize = false,
bool showInDiscoveryDocument = true,
bool enabled = true)
{
Check.NotNull(name, nameof(name));
ApiResourceId = apiResourceId;
Id = id;
Name = name;
DisplayName = displayName ?? name;
Description = description;
Required = required;
Emphasize = emphasize;
ShowInDiscoveryDocument = showInDiscoveryDocument;
Enabled = enabled;
UserClaims = new List<ApiScopeClaim>();
Properties = new List<ApiScopeProperty>();
}
public virtual void AddUserClaim([NotNull] string type)
{
UserClaims.Add(new ApiScopeClaim(ApiResourceId, Name, type));
UserClaims.Add(new ApiScopeClaim(Id, type));
}
public virtual void RemoveAllUserClaims()
@ -74,12 +74,27 @@ namespace Volo.Abp.IdentityServer.ApiResources
public virtual ApiScopeClaim FindClaim(string type)
{
return UserClaims.FirstOrDefault(r => r.Name == Name && r.Type == type);
return UserClaims.FirstOrDefault(r => r.Type == type);
}
public virtual void AddProperty([NotNull] string key, string value)
{
Properties.Add(new ApiScopeProperty(Id, key, value));
}
public virtual void RemoveAllProperties()
{
Properties.Clear();
}
public virtual void RemoveProperty(string key)
{
Properties.RemoveAll(r => r.Key == key);
}
public override object[] GetKeys()
public virtual ApiScopeProperty FindProperty(string key)
{
return new object[] { ApiResourceId, Name };
return Properties.FirstOrDefault(r => r.Key == key);
}
}
}
}

31
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScopeClaim.cs

@ -0,0 +1,31 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScopeClaim : UserClaim
{
public Guid ApiScopeId { get; protected set; }
protected ApiScopeClaim()
{
}
public virtual bool Equals(Guid apiScopeId, [NotNull] string type)
{
return ApiScopeId == apiScopeId && Type == type;
}
protected internal ApiScopeClaim(Guid apiScopeId, [NotNull] string type)
: base(type)
{
ApiScopeId = apiScopeId;
}
public override object[] GetKeys()
{
return new object[] { ApiScopeId, Type };
}
}
}

39
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/ApiScopeProperty.cs

@ -0,0 +1,39 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScopeProperty : Entity
{
public virtual Guid ApiScopeId { get; set; }
public virtual string Key { get; set; }
public virtual string Value { get; set; }
protected ApiScopeProperty()
{
}
public virtual bool Equals(Guid apiScopeId, [NotNull] string key, string value)
{
return ApiScopeId == apiScopeId && Key == key && Value == value;
}
protected internal ApiScopeProperty(Guid apiScopeId, [NotNull] string key, [NotNull] string value)
{
Check.NotNull(key, nameof(key));
ApiScopeId = apiScopeId;
Key = key;
Value = value;
}
public override object[] GetKeys()
{
return new object[] { ApiScopeId, Key };
}
}
}

38
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiScopes/IApiScopeeRepository.cs

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.IdentityServer.ApiScopes
{
public interface IApiScopeRepository : IBasicRepository<ApiScope, Guid>
{
Task<ApiScope> GetByNameAsync(
string scopeName,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
Task<List<ApiScope>> GetListByNameAsync(
string[] scopeNames,
bool includeDetails = false,
CancellationToken cancellationToken = default
);
Task<List<ApiScope>> GetListAsync(
string sorting,
int skipCount,
int maxResultCount,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default
);
Task<bool> CheckNameExistAsync(
string name,
Guid? expectedId = null,
CancellationToken cancellationToken = default
);
}
}

10
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
@ -27,7 +27,6 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
protected SignInManager<IdentityUser> SignInManager { get; }
protected IEventService Events { get; }
protected UserManager<IdentityUser> UserManager { get; }
protected IdentitySecurityLogManager IdentitySecurityLogManager { get; }
protected ILogger<ResourceOwnerPasswordValidator<IdentityUser>> Logger { get; }
@ -39,7 +38,6 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
IdentitySecurityLogManager identitySecurityLogManager,
IEventService events,
ILogger<ResourceOwnerPasswordValidator<IdentityUser>> logger,
IStringLocalizer<AbpIdentityServerResource> localizer,
IOptions<AbpIdentityOptions> abpIdentityOptions,
@ -48,7 +46,6 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
UserManager = userManager;
SignInManager = signInManager;
IdentitySecurityLogManager = identitySecurityLogManager;
Events = events;
Logger = logger;
Localizer = localizer;
ServiceScopeFactory = serviceScopeFactory;
@ -75,7 +72,6 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
var sub = await UserManager.GetUserIdAsync(user);
Logger.LogInformation("Credentials validated for username: {username}", context.UserName);
await Events.RaiseAsync(new UserLoginSuccessEvent(context.UserName, sub, context.UserName, interactive: false));
var additionalClaims = new List<Claim>();
@ -136,19 +132,16 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
else if (result.IsLockedOut)
{
Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", context.UserName);
await Events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "locked out", interactive: false));
errorDescription = Localizer["UserLockedOut"];
}
else if (result.IsNotAllowed)
{
Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", context.UserName);
await Events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "not allowed", interactive: false));
errorDescription = Localizer["LoginIsNotAllowed"];
}
else
{
Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", context.UserName);
await Events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid credentials", interactive: false));
errorDescription = Localizer["InvalidUserNameOrPassword"];
}
@ -163,7 +156,6 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity
else
{
Logger.LogInformation("No user found matching username: {username}", context.UserName);
await Events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid username", interactive: false));
errorDescription = Localizer["InvalidUsername"];
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs

@ -36,6 +36,8 @@ namespace Volo.Abp.IdentityServer.Clients
public virtual bool AllowPlainTextPkce { get; set; }
public virtual bool RequireRequestObject { get; set; }
public virtual bool AllowAccessTokensViaBrowser { get; set; }
public virtual string FrontChannelLogoutUri { get; set; }
@ -50,6 +52,8 @@ namespace Volo.Abp.IdentityServer.Clients
public virtual int IdentityTokenLifetime { get; set; }
public virtual string AllowedIdentityTokenSigningAlgorithms { get; set; }
public virtual int AccessTokenLifetime { get; set; }
public virtual int AuthorizationCodeLifetime { get; set; }
@ -118,8 +122,9 @@ namespace Volo.Abp.IdentityServer.Clients
ProtocolType = IdentityServerConstants.ProtocolTypes.OpenIdConnect;
RequireClientSecret = true;
RequireConsent = true;
RequireConsent = false;
AllowRememberConsent = true;
RequirePkce = true;
FrontChannelLogoutSessionRequired = true;
BackChannelLogoutSessionRequired = true;
IdentityTokenLifetime = 300;
@ -319,4 +324,4 @@ namespace Volo.Abp.IdentityServer.Clients
return IdentityProviderRestrictions.FirstOrDefault(r => r.Provider == provider);
}
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientProperty.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.IdentityServer.Clients
}
public virtual bool Equals(Guid clientId, [NotNull] string key, string value)
public virtual bool Equals(Guid clientId, [NotNull] string key, [NotNull] string value)
{
return ClientId == clientId && Key == key && Value == value;
}
@ -36,4 +36,4 @@ namespace Volo.Abp.IdentityServer.Clients
return new object[] { ClientId, Key };
}
}
}
}

2
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.IdentityServer.Clients
public virtual async Task<IdentityServer4.Models.Client> FindClientByIdAsync(string clientId)
{
var client = await ClientRepository.FindByCliendIdAsync(clientId);
var client = await ClientRepository.FindByClientIdAsync(clientId);
return ObjectMapper.Map<Client, IdentityServer4.Models.Client>(client);
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/IClientRepository.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.IdentityServer.Clients
{
public interface IClientRepository : IBasicRepository<Client, Guid>
{
Task<Client> FindByCliendIdAsync(
Task<Client> FindByClientIdAsync(
[NotNull] string clientId,
bool includeDetails = true,
CancellationToken cancellationToken = default
@ -32,4 +32,4 @@ namespace Volo.Abp.IdentityServer.Clients
CancellationToken cancellationToken = default
);
}
}
}

6
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowCodes.cs

@ -11,8 +11,12 @@ namespace Volo.Abp.IdentityServer.Devices
public virtual string SubjectId { get; set; }
public virtual string SessionId { get; set; }
public virtual string ClientId { get; set; }
public virtual string Description { get; set; }
public virtual DateTime? Expiration { get; set; }
public virtual string Data { get; set; }
@ -28,4 +32,4 @@ namespace Volo.Abp.IdentityServer.Devices
}
}
}
}

21
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs

@ -8,6 +8,12 @@ namespace Volo.Abp.IdentityServer.Grants
{
public interface IPersistentGrantRepository : IBasicRepository<PersistedGrant, Guid>
{
Task<List<PersistedGrant>> GetListAsync(
string subjectId,
string sessionId,
string clientId,
string type, bool includeDetails = false, CancellationToken cancellationToken = default);
Task<PersistedGrant> FindByKeyAsync(
string key,
CancellationToken cancellationToken = default
@ -25,16 +31,11 @@ namespace Volo.Abp.IdentityServer.Grants
);
Task DeleteAsync(
string subjectId,
string clientId,
CancellationToken cancellationToken = default
);
Task DeleteAsync(
string subjectId,
string clientId,
string type,
string subjectId = null,
string sessionId = null,
string clientId = null,
string type = null,
CancellationToken cancellationToken = default
);
}
}
}

12
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrant.cs

@ -1,4 +1,4 @@
using System;
using System;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.IdentityServer.Grants
@ -11,17 +11,23 @@ namespace Volo.Abp.IdentityServer.Grants
public virtual string SubjectId { get; set; }
public virtual string SessionId { get; set; }
public virtual string ClientId { get; set; }
public virtual string Description { get; set; }
public virtual DateTime CreationTime { get; set; }
public virtual DateTime? Expiration { get; set; }
public virtual DateTime? ConsumedTime { get; set; }
public virtual string Data { get; set; }
protected PersistedGrant()
{
}
public PersistedGrant(Guid id)
@ -29,4 +35,4 @@ namespace Volo.Abp.IdentityServer.Grants
Id = id;
}
}
}
}

15
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs

@ -44,10 +44,10 @@ namespace Volo.Abp.IdentityServer.Grants
return ObjectMapper.Map<PersistedGrant, IdentityServer4.Models.PersistedGrant>(persistedGrant);
}
public virtual async Task<IEnumerable<IdentityServer4.Models.PersistedGrant>> GetAllAsync(string subjectId)
public virtual async Task<IEnumerable<IdentityServer4.Models.PersistedGrant>> GetAllAsync(PersistedGrantFilter filter)
{
var persistedGrants = await PersistentGrantRepository.GetListBySubjectIdAsync(subjectId);
return persistedGrants.Select(x => ObjectMapper.Map<PersistedGrant, IdentityServer4.Models.PersistedGrant>(x));
var persistedGrants = await PersistentGrantRepository.GetListAsync(filter.SubjectId, filter.SessionId, filter.ClientId, filter.Type);
return ObjectMapper.Map<List<PersistedGrant>, List<IdentityServer4.Models.PersistedGrant>>(persistedGrants);
}
public virtual async Task RemoveAsync(string key)
@ -61,14 +61,9 @@ namespace Volo.Abp.IdentityServer.Grants
await PersistentGrantRepository.DeleteAsync(persistedGrant);
}
public virtual async Task RemoveAllAsync(string subjectId, string clientId)
public virtual async Task RemoveAllAsync(PersistedGrantFilter filter)
{
await PersistentGrantRepository.DeleteAsync(subjectId, clientId);
}
public virtual async Task RemoveAllAsync(string subjectId, string clientId, string type)
{
await PersistentGrantRepository.DeleteAsync(subjectId, clientId, type);
await PersistentGrantRepository.DeleteAsync(filter.SubjectId, filter.SessionId, filter.ClientId, filter.Type);
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources
{
public interface IIdentityResourceRepository : IBasicRepository<IdentityResource, Guid>
{
Task<List<IdentityResource>> GetListByScopesAsync(
Task<List<IdentityResource>> GetListByScopeNameAsync(
string[] scopeNames,
bool includeDetails = false,
CancellationToken cancellationToken = default
@ -35,4 +35,4 @@ namespace Volo.Abp.IdentityServer.IdentityResources
CancellationToken cancellationToken = default
);
}
}
}

52
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResource.cs

@ -22,9 +22,9 @@ namespace Volo.Abp.IdentityServer.IdentityResources
public virtual bool ShowInDiscoveryDocument { get; set; }
public virtual List<IdentityClaim> UserClaims { get; set; }
public virtual List<IdentityResourceClaim> UserClaims { get; set; }
public virtual Dictionary<string, string> Properties { get; set; }
public virtual List<IdentityResourceProperty> Properties { get; set; }
protected IdentityResource()
{
@ -32,13 +32,13 @@ namespace Volo.Abp.IdentityServer.IdentityResources
}
public IdentityResource(
Guid id,
[NotNull] string name,
string displayName = null,
string description = null,
bool enabled = true,
bool required = false,
bool emphasize = false,
Guid id,
[NotNull] string name,
string displayName = null,
string description = null,
bool enabled = true,
bool required = false,
bool emphasize = false,
bool showInDiscoveryDocument = true)
{
Check.NotNull(name, nameof(name));
@ -51,9 +51,9 @@ namespace Volo.Abp.IdentityServer.IdentityResources
Required = required;
Emphasize = emphasize;
ShowInDiscoveryDocument = showInDiscoveryDocument;
UserClaims = new List<IdentityClaim>();
Properties = new Dictionary<string, string>();
UserClaims = new List<IdentityResourceClaim>();
Properties = new List<IdentityResourceProperty>();
}
public IdentityResource(Guid id, IdentityServer4.Models.IdentityResource resource)
@ -66,13 +66,13 @@ namespace Volo.Abp.IdentityServer.IdentityResources
Required = resource.Required;
Emphasize = resource.Emphasize;
ShowInDiscoveryDocument = resource.ShowInDiscoveryDocument;
UserClaims = resource.UserClaims.Select(claimType => new IdentityClaim(id, claimType)).ToList();
Properties = resource.Properties.ToDictionary(x => x.Key, x => x.Value);
UserClaims = resource.UserClaims.Select(claimType => new IdentityResourceClaim(id, claimType)).ToList();
Properties = resource.Properties.Select(x => new IdentityResourceProperty(Id, x.Key, x.Value)).ToList();
}
public virtual void AddUserClaim([NotNull] string type)
{
UserClaims.Add(new IdentityClaim(Id, type));
UserClaims.Add(new IdentityResourceClaim(Id, type));
}
public virtual void RemoveAllUserClaims()
@ -85,9 +85,29 @@ namespace Volo.Abp.IdentityServer.IdentityResources
UserClaims.RemoveAll(c => c.Type == type);
}
public virtual IdentityClaim FindUserClaim(string type)
public virtual IdentityResourceClaim FindUserClaim(string type)
{
return UserClaims.FirstOrDefault(c => c.Type == type);
}
public virtual void AddProperty([NotNull] string key, string value)
{
Properties.Add(new IdentityResourceProperty(Id, key, value));
}
public virtual void RemoveAllProperties()
{
Properties.Clear();
}
public virtual void RemoveProperty(string key)
{
Properties.RemoveAll(r => r.Key == key);
}
public virtual IdentityResourceProperty FindProperty(string key)
{
return Properties.FirstOrDefault(r => r.Key == key);
}
}
}

8
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityClaim.cs → modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceClaim.cs

@ -3,11 +3,11 @@ using JetBrains.Annotations;
namespace Volo.Abp.IdentityServer.IdentityResources
{
public class IdentityClaim : UserClaim
public class IdentityResourceClaim : UserClaim
{
public virtual Guid IdentityResourceId { get; set; }
protected IdentityClaim()
protected IdentityResourceClaim()
{
}
@ -17,7 +17,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources
return IdentityResourceId == identityResourceId && Type == type;
}
protected internal IdentityClaim(Guid identityResourceId, [NotNull] string type)
protected internal IdentityResourceClaim(Guid identityResourceId, [NotNull] string type)
: base(type)
{
IdentityResourceId = identityResourceId;
@ -28,4 +28,4 @@ namespace Volo.Abp.IdentityServer.IdentityResources
return new object[] { IdentityResourceId, Type };
}
}
}
}

39
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceProperty.cs

@ -0,0 +1,39 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.IdentityServer.IdentityResources
{
public class IdentityResourceProperty : Entity
{
public virtual Guid IdentityResourceId { get; set; }
public virtual string Key { get; set; }
public virtual string Value { get; set; }
protected IdentityResourceProperty()
{
}
public virtual bool Equals(Guid identityResourceId, [NotNull] string key, string value)
{
return IdentityResourceId == identityResourceId && Key == key && Value == value;
}
protected internal IdentityResourceProperty(Guid identityResourceId, [NotNull] string key, [NotNull] string value)
{
Check.NotNull(key, nameof(key));
IdentityResourceId = identityResourceId;
Key = key;
Value = value;
}
public override object[] GetKeys()
{
return new object[] { IdentityResourceId, Key };
}
}
}

105
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerAutoMapperProfile.cs

@ -2,6 +2,7 @@
using System.Security.Claims;
using AutoMapper;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -11,40 +12,39 @@ namespace Volo.Abp.IdentityServer
{
public class IdentityServerAutoMapperProfile : Profile
{
/// <summary>
/// TODO: Reverse maps will not used probably. Remove those will not used
/// </summary>
public IdentityServerAutoMapperProfile()
{
//TODO: Reverse maps will not used probably. Remove those will not used
CreateMap<Client, IdentityServer4.Models.Client>();
CreateMap<ClientCorsOrigin, string>()
.ConstructUsing(src => src.Origin)
.ReverseMap()
.ForMember(dest => dest.Origin, opt => opt.MapFrom(src => src));
CreateMap<ApiResource, IdentityServer4.Models.ApiResource>()
.ForMember(dest => dest.ApiSecrets, opt => opt.MapFrom(src => src.Secrets));
//TODO: Why PersistedGrant mapping is in this profile?
CreateMap<PersistedGrant, IdentityServer4.Models.PersistedGrant>().ReverseMap();
CreateMap<IdentityResource, IdentityServer4.Models.IdentityResource>();
CreateMap<UserClaim, string>()
.ConstructUsing(src => src.Type)
.ReverseMap()
.ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
CreateMap<ApiSecret, IdentityServer4.Models.Secret>();
CreateClientMap();
CreateApiResourceMap();
CreateApiScopeMap();
CreateIdentityResourceMap();
CreatePersistedGrantMap();
CreateDeviceFlowCodesMap();
}
CreateMap<ApiScope, IdentityServer4.Models.Scope>();
private void CreateClientMap()
{
CreateMap<ClientCorsOrigin, string>()
.ConstructUsing(src => src.Origin)
.ReverseMap()
.ForMember(dest => dest.Origin, opt => opt.MapFrom(src => src));
CreateMap<ClientProperty, KeyValuePair<string, string>>()
CreateMap<ClientProperty, KeyValuePair<string, string>>()
.ReverseMap();
CreateMap<Client, IdentityServer4.Models.Client>()
.ForMember(dest => dest.ProtocolType, opt => opt.Condition(srs => srs != null))
.ReverseMap();
.ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms))
.ReverseMap()
.ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms));
CreateMap<ClientCorsOrigin, string>()
.ConstructUsing(src => src.Origin)
@ -60,6 +60,10 @@ namespace Volo.Abp.IdentityServer
.ConstructUsing(src => new Claim(src.Type, src.Value))
.ReverseMap();
CreateMap<ClientClaim, IdentityServer4.Models.ClientClaim>(MemberList.None)
.ConstructUsing(src => new IdentityServer4.Models.ClientClaim(src.Type, src.Value, ClaimValueTypes.String))
.ReverseMap();
CreateMap<ClientScope, string>()
.ConstructUsing(src => src.Scope)
.ReverseMap()
@ -86,9 +90,64 @@ namespace Volo.Abp.IdentityServer
CreateMap<ApiResource, ApiResourceEto>();
CreateMap<Client, ClientEto>();
CreateMap<DeviceFlowCodes, DeviceFlowCodesEto>();
CreateMap<PersistedGrant, PersistedGrantEto>();
}
private void CreateApiResourceMap()
{
CreateMap<ApiResource, IdentityServer4.Models.ApiResource>()
.ForMember(dest => dest.ApiSecrets, opt => opt.MapFrom(src => src.Secrets));
CreateMap<ApiResourceSecret, IdentityServer4.Models.Secret>();
CreateMap<ApiResourceScope, string>()
.ConstructUsing(x => x.Scope)
.ReverseMap()
.ForMember(dest => dest.Scope, opt => opt.MapFrom(src => src));
CreateMap<ApiResource, ApiResourceEto>();
}
private void CreateApiScopeMap()
{
CreateMap<ApiScopeProperty, KeyValuePair<string, string>>()
.ReverseMap();
CreateMap<ApiScopeClaim, string>()
.ConstructUsing(x => x.Type)
.ReverseMap()
.ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
CreateMap<ApiScope, IdentityServer4.Models.ApiScope>(MemberList.Destination)
.ConstructUsing(src => new IdentityServer4.Models.ApiScope())
.ReverseMap();
}
private void CreateIdentityResourceMap()
{
CreateMap<IdentityResource, IdentityServer4.Models.IdentityResource>()
.ConstructUsing(src => new IdentityServer4.Models.IdentityResource());
CreateMap<IdentityResourceClaim, string>()
.ConstructUsing(x => x.Type)
.ReverseMap()
.ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
CreateMap<IdentityResourceProperty, KeyValuePair<string, string>>()
.ReverseMap();
CreateMap<IdentityResource, IdentityResourceEto>();
}
private void CreatePersistedGrantMap()
{
//TODO: Why PersistedGrant mapping is in this profile?
CreateMap<PersistedGrant, IdentityServer4.Models.PersistedGrant>().ReverseMap();
CreateMap<PersistedGrant, PersistedGrantEto>();
}
private void CreateDeviceFlowCodesMap()
{
CreateMap<DeviceFlowCodes, DeviceFlowCodesEto>();
}
}
}

60
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs

@ -1,13 +1,12 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.ObjectMapping;
using ApiResource = IdentityServer4.Models.ApiResource;
using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource;
namespace Volo.Abp.IdentityServer
{
@ -15,45 +14,70 @@ namespace Volo.Abp.IdentityServer
{
protected IIdentityResourceRepository IdentityResourceRepository { get; }
protected IApiResourceRepository ApiResourceRepository { get; }
protected IApiScopeRepository ApiScopeRepository { get; }
protected IObjectMapper<AbpIdentityServerDomainModule> ObjectMapper { get; }
public ResourceStore(
IIdentityResourceRepository identityResourceRepository,
IObjectMapper<AbpIdentityServerDomainModule> objectMapper,
IApiResourceRepository apiResourceRepository)
IIdentityResourceRepository identityResourceRepository,
IObjectMapper<AbpIdentityServerDomainModule> objectMapper,
IApiResourceRepository apiResourceRepository,
IApiScopeRepository apiScopeRepository)
{
IdentityResourceRepository = identityResourceRepository;
ObjectMapper = objectMapper;
ApiResourceRepository = apiResourceRepository;
ApiScopeRepository = apiScopeRepository;
}
public virtual async Task<IEnumerable<IdentityServer4.Models.IdentityResource>> FindIdentityResourcesByScopeAsync(IEnumerable<string> scopeNames)
/// <summary>
/// Gets identity resources by scope name.
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.IdentityResource>> FindIdentityResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
var resource = await IdentityResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(resource);
var resource = await IdentityResourceRepository.GetListByScopeNameAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.IdentityResources.IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(resource);
}
public virtual async Task<IEnumerable<ApiResource>> FindApiResourcesByScopeAsync(IEnumerable<string> scopeNames)
/// <summary>
/// Gets API scopes by scope name.
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiScope>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)
{
var scopes = await ApiScopeRepository.GetListByNameAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiScopes.ApiScope>, List<IdentityServer4.Models.ApiScope>>(scopes);
}
/// <summary>
/// Gets API resources by scope name.
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiResource>> FindApiResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
var resources = await ApiResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true);
return resources.Select(x => ObjectMapper.Map<ApiResources.ApiResource, ApiResource>(x));
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(resources);
}
public virtual async Task<ApiResource> FindApiResourceAsync(string name)
/// <summary>
/// Gets API resources by API resource name.
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiResource>> FindApiResourcesByNameAsync(IEnumerable<string> apiResourceNames)
{
var resource = await ApiResourceRepository.FindByNameAsync(name);
return ObjectMapper.Map<ApiResources.ApiResource, ApiResource>(resource);
var resources = await ApiResourceRepository.FindByNameAsync(apiResourceNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(resources);
}
public virtual async Task<Resources> GetAllResourcesAsync()
/// <summary>
/// Gets all resources.
/// </summary>
public virtual async Task<IdentityServer4.Models.Resources> GetAllResourcesAsync()
{
var identityResources = await IdentityResourceRepository.GetListAsync(includeDetails: true);
var apiResources = await ApiResourceRepository.GetListAsync(includeDetails: true);
var apiScopes = await ApiScopeRepository.GetListAsync(includeDetails: true);
return new Resources(
ObjectMapper.Map<List<IdentityResource>, IdentityServer4.Models.IdentityResource[]>(identityResources),
ObjectMapper.Map<List<ApiResources.ApiResource>, ApiResource[]>(apiResources)
);
ObjectMapper.Map<List<Volo.Abp.IdentityServer.IdentityResources.IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(identityResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(apiResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiScopes.ApiScope>, List<IdentityServer4.Models.ApiScope>>(apiScopes));
}
}
}

19
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/AbpIdentityServerEfCoreQueryableExtensions.cs

@ -1,6 +1,7 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.IdentityResources;
@ -20,9 +21,22 @@ namespace Volo.Abp.IdentityServer
.Include(x => x.Secrets)
.Include(x => x.UserClaims)
.Include(x => x.Scopes)
.ThenInclude(s => s.UserClaims);
.Include(x => x.Properties);
}
public static IQueryable<ApiScope> IncludeDetails(this IQueryable<ApiScope> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.UserClaims)
.Include(x => x.Properties);
}
public static IQueryable<IdentityResource> IncludeDetails(this IQueryable<IdentityResource> queryable, bool include = true)
{
if (!include)
@ -31,7 +45,8 @@ namespace Volo.Abp.IdentityServer
}
return queryable
.Include(x => x.UserClaims);
.Include(x => x.UserClaims)
.Include(x => x.Properties);
}
public static IQueryable<Client> IncludeDetails(this IQueryable<Client> queryable, bool include = true)

65
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using System.Linq.Dynamic.Core;
using System.Runtime.InteropServices.ComTypes;
namespace Volo.Abp.IdentityServer.ApiResources
{
@ -19,18 +18,24 @@ namespace Volo.Abp.IdentityServer.ApiResources
}
public virtual async Task<ApiResource> FindByNameAsync(
string name,
bool includeDetails = true,
public async Task<ApiResource> FindByNameAsync(string apiResourceName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
var query = from apiResource in DbSet.IncludeDetails(includeDetails)
where apiResource.Name == apiResourceName
select apiResource;
return await query.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<ApiResource>> FindByNameAsync(string[] apiResourceNames, bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var query = from apiResource in DbSet.IncludeDetails(includeDetails)
where apiResource.Name == name
orderby apiResource.Name
select apiResource;
where apiResourceNames.Contains(apiResource.Name)
orderby apiResource.Name
select apiResource;
return await query
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
return await query.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<ApiResource>> GetListByScopesAsync(
@ -39,14 +44,17 @@ namespace Volo.Abp.IdentityServer.ApiResources
CancellationToken cancellationToken = default)
{
var query = from api in DbSet.IncludeDetails(includeDetails)
where api.Scopes.Any(x => scopeNames.Contains(x.Name))
where api.Scopes.Any(x => scopeNames.Contains(x.Scope))
select api;
return await query.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<ApiResource>> GetListAsync(
string sorting, int skipCount, int maxResultCount, string filter, bool includeDetails = false,
string sorting, int skipCount,
int maxResultCount,
string filter,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await DbSet
@ -59,34 +67,35 @@ namespace Volo.Abp.IdentityServer.ApiResources
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<ApiResource>> GetListAsync(
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<bool> CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default)
{
return await DbSet.AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken);
return await DbSet.AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken));
}
public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default)
{
var scopeClaims = DbContext.Set<ApiScopeClaim>().Where(sc => sc.ApiResourceId == id);
var resourceClaims = DbContext.Set<ApiResourceClaim>().Where(sc => sc.ApiResourceId == id);
foreach (var scopeClaim in resourceClaims)
{
DbContext.Set<ApiResourceClaim>().Remove(scopeClaim);
}
foreach (var scopeClaim in scopeClaims)
var resourceScopes = DbContext.Set<ApiResourceScope>().Where(s => s.ApiResourceId == id);
foreach (var scope in resourceScopes)
{
DbContext.Set<ApiScopeClaim>().Remove(scopeClaim);
DbContext.Set<ApiResourceScope>().Remove(scope);
}
var scopes = DbContext.Set<ApiScope>().Where(s => s.ApiResourceId == id);
var resourceSecrets = DbContext.Set<ApiResourceSecret>().Where(s => s.ApiResourceId == id);
foreach (var secret in resourceSecrets)
{
DbContext.Set<ApiResourceSecret>().Remove(secret);
}
foreach (var scope in scopes)
var apiResourceProperties = DbContext.Set<ApiResourceProperty>().Where(s => s.ApiResourceId == id);
foreach (var property in apiResourceProperties)
{
DbContext.Set<ApiScope>().Remove(scope);
DbContext.Set<ApiResourceProperty>().Remove(property);
}
await base.DeleteAsync(id, autoSave, cancellationToken);

75
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
namespace Volo.Abp.IdentityServer.ApiScopes
{
public class ApiScopeRepository : EfCoreRepository<IIdentityServerDbContext, ApiScope, Guid>, IApiScopeRepository
{
public ApiScopeRepository(IDbContextProvider<IIdentityServerDbContext> dbContextProvider) : base(
dbContextProvider)
{
}
public async Task<ApiScope> GetByNameAsync(string scopeName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await DbSet.FirstOrDefaultAsync(x => x.Name == scopeName, GetCancellationToken(cancellationToken));
}
public async Task<List<ApiScope>> GetListByNameAsync(string[] scopeNames, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var query = from scope in DbSet.IncludeDetails(includeDetails)
where scopeNames.Contains(scope.Name)
select scope;
return await query.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<ApiScope>> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) ||
x.Description.Contains(filter) ||
x.DisplayName.Contains(filter))
.OrderBy(sorting ?? "name desc")
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<bool> CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default)
{
return await DbSet.AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken));
}
public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = new CancellationToken())
{
var scopeClaims = DbContext.Set<ApiScopeClaim>().Where(sc => sc.ApiScopeId == id);
foreach (var claim in scopeClaims)
{
DbContext.Set<ApiScopeClaim>().Remove(claim);
}
var scopeProperties = DbContext.Set<ApiScopeProperty>().Where(s => s.ApiScopeId == id);
foreach (var property in scopeProperties)
{
DbContext.Set<ApiScopeProperty>().Remove(property);
}
await base.DeleteAsync(id, autoSave, cancellationToken);
}
public override IQueryable<ApiScope> WithDetails()
{
return GetQueryable().IncludeDetails();
}
}
}

2
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs

@ -18,7 +18,7 @@ namespace Volo.Abp.IdentityServer.Clients
}
public virtual async Task<Client> FindByCliendIdAsync(
public virtual async Task<Client> FindByClientIdAsync(
string clientId,
bool includeDetails = true,
CancellationToken cancellationToken = default)

2
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -33,6 +34,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
options.AddRepository<Client, ClientRepository>();
options.AddRepository<ApiResource, ApiResourceRepository>();
options.AddRepository<ApiScope, ApiScopeRepository>();
options.AddRepository<IdentityResource, IdentityResourceRepository>();
options.AddRepository<PersistedGrant, PersistentGrantRepository>();
options.AddRepository<DeviceFlowCodes, DeviceFlowCodesRepository>();

29
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs

@ -2,6 +2,7 @@
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -12,19 +13,41 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
[ConnectionStringName(AbpIdentityServerDbProperties.ConnectionStringName)]
public interface IIdentityServerDbContext : IEfCoreDbContext
{
#region ApiResource
DbSet<ApiResource> ApiResources { get; set; }
DbSet<ApiSecret> ApiSecrets { get; set; }
DbSet<ApiResourceSecret> ApiResourceSecrets { get; set; }
DbSet<ApiResourceClaim> ApiResourceClaims { get; set; }
DbSet<ApiResourceScope> ApiResourceScopes { get; set; }
DbSet<ApiResourceProperty> ApiResourceProperties { get; set; }
#endregion
#region ApiScope
DbSet<ApiScope> ApiScopes { get; set; }
DbSet<ApiScopeClaim> ApiScopeClaims { get; set; }
DbSet<ApiScopeProperty> ApiScopeProperties { get; set; }
#endregion
#region IdentityResource
DbSet<IdentityResource> IdentityResources { get; set; }
DbSet<IdentityClaim> IdentityClaims { get; set; }
DbSet<IdentityResourceClaim> IdentityClaims { get; set; }
DbSet<IdentityResourceProperty> IdentityResourceProperties { get; set; }
#endregion
#region Client
DbSet<Client> Clients { get; set; }
@ -46,6 +69,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
DbSet<ClientProperty> ClientProperties { get; set; }
#endregion
DbSet<PersistedGrant> PersistedGrants { get; set; }
DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }

29
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs

@ -2,6 +2,7 @@
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -12,19 +13,41 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
[ConnectionStringName(AbpIdentityServerDbProperties.ConnectionStringName)]
public class IdentityServerDbContext : AbpDbContext<IdentityServerDbContext>, IIdentityServerDbContext
{
#region ApiResource
public DbSet<ApiResource> ApiResources { get; set; }
public DbSet<ApiSecret> ApiSecrets { get; set; }
public DbSet<ApiResourceSecret> ApiResourceSecrets { get; set; }
public DbSet<ApiResourceClaim> ApiResourceClaims { get; set; }
public DbSet<ApiResourceScope> ApiResourceScopes { get; set; }
public DbSet<ApiResourceProperty> ApiResourceProperties { get; set; }
#endregion
#region ApiScope
public DbSet<ApiScope> ApiScopes { get; set; }
public DbSet<ApiScopeClaim> ApiScopeClaims { get; set; }
public DbSet<ApiScopeProperty> ApiScopeProperties { get; set; }
#endregion
#region IdentityResource
public DbSet<IdentityResource> IdentityResources { get; set; }
public DbSet<IdentityClaim> IdentityClaims { get; set; }
public DbSet<IdentityResourceClaim> IdentityClaims { get; set; }
public DbSet<IdentityResourceProperty> IdentityResourceProperties { get; set; }
#endregion
#region Client
public DbSet<Client> Clients { get; set; }
@ -46,6 +69,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
public DbSet<ClientProperty> ClientProperties { get; set; }
#endregion
public DbSet<PersistedGrant> PersistedGrants { get; set; }
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }

227
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs

@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueComparers;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -28,6 +26,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
optionsAction?.Invoke(options);
#region Client
builder.Entity<Client>(b =>
{
b.ToTable(options.TablePrefix + "Clients", options.Schema);
@ -45,6 +45,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.Property(x => x.ClientClaimsPrefix).HasMaxLength(ClientConsts.ClientClaimsPrefixMaxLength);
b.Property(x => x.PairWiseSubjectSalt).HasMaxLength(ClientConsts.PairWiseSubjectSaltMaxLength);
b.Property(x => x.UserCodeType).HasMaxLength(ClientConsts.UserCodeTypeMaxLength);
b.Property(x => x.AllowedIdentityTokenSigningAlgorithms).HasMaxLength(ClientConsts.AllowedIdentityTokenSigningAlgorithms);
b.HasMany(x => x.AllowedScopes).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
b.HasMany(x => x.ClientSecrets).WithOne().HasForeignKey(x => x.ClientId).IsRequired();
@ -81,8 +82,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
{
ClientRedirectUriConsts.RedirectUriMaxLengthValue = 300;
}
}
b.Property(x => x.RedirectUri).HasMaxLength(ClientRedirectUriConsts.RedirectUriMaxLengthValue).IsRequired();
});
@ -97,8 +98,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
{
ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLengthValue = 300;
}
}
b.Property(x => x.PostLogoutRedirectUri)
.HasMaxLength(ClientPostLogoutRedirectUriConsts.PostLogoutRedirectUriMaxLengthValue)
.IsRequired();
@ -123,16 +124,13 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.HasKey(x => new {x.ClientId, x.Type, x.Value});
b.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
b.Property(x => x.Type).HasMaxLength(ClientSecretConsts.TypeMaxLength).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
{
SecretConsts.ValueMaxLengthValue = 300;
ClientSecretConsts.ValueMaxLength = 300;
}
b.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLengthValue).IsRequired();
b.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
b.Property(x => x.Value).HasMaxLength(ClientSecretConsts.ValueMaxLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(ClientSecretConsts.DescriptionMaxLength);
});
builder.Entity<ClientClaim>(b =>
@ -175,36 +173,15 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.ConfigureByConvention();
b.HasKey(x => new {x.ClientId, x.Key});
b.HasKey(x => new {x.ClientId, x.Key, x.Value});
b.Property(x => x.Key).HasMaxLength(ClientPropertyConsts.KeyMaxLength).IsRequired();
b.Property(x => x.Value).HasMaxLength(ClientPropertyConsts.ValueMaxLength).IsRequired();
});
builder.Entity<PersistedGrant>(b =>
{
b.ToTable(options.TablePrefix + "PersistedGrants", options.Schema);
b.ConfigureByConvention();
b.Property(x => x.Key).HasMaxLength(PersistedGrantConsts.KeyMaxLength).ValueGeneratedNever();
b.Property(x => x.Type).HasMaxLength(PersistedGrantConsts.TypeMaxLength).IsRequired();
b.Property(x => x.SubjectId).HasMaxLength(PersistedGrantConsts.SubjectIdMaxLength);
b.Property(x => x.ClientId).HasMaxLength(PersistedGrantConsts.ClientIdMaxLength).IsRequired();
b.Property(x => x.CreationTime).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
{
PersistedGrantConsts.DataMaxLengthValue = 10000; //TODO: MySQL accepts 20.000. We can consider to change in v3.0.
}
b.Property(x => x.Data).HasMaxLength(PersistedGrantConsts.DataMaxLengthValue).IsRequired();
b.HasKey(x => x.Key); //TODO: What about Id!!!
#endregion
b.HasIndex(x => new {x.SubjectId, x.ClientId, x.Type});
b.HasIndex(x => x.Expiration);
});
#region IdentityResource
builder.Entity<IdentityResource>(b =>
{
@ -215,16 +192,16 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.Property(x => x.Name).HasMaxLength(IdentityResourceConsts.NameMaxLength).IsRequired();
b.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength);
b.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength);
b.Property(x => x.Properties)
.HasConversion(new AbpJsonValueConverter<Dictionary<string, string>>())
.Metadata.SetValueComparer(new AbpDictionaryValueComparer<string, string>());
b.HasIndex(x => x.Name).IsUnique();
b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired();
});
builder.Entity<IdentityClaim>(b =>
builder.Entity<IdentityResourceClaim>(b =>
{
b.ToTable(options.TablePrefix + "IdentityClaims", options.Schema);
b.ToTable(options.TablePrefix + "IdentityResourceClaims", options.Schema);
b.ConfigureByConvention();
@ -233,46 +210,67 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
});
builder.Entity<ApiResource>(b =>
builder.Entity<IdentityResourceProperty>(b =>
{
b.ToTable(options.TablePrefix + "IdentityResourceProperties", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.IdentityResourceId, x.Key, x.Value});
b.Property(x => x.Key).HasMaxLength(IdentityResourcePropertyConsts.KeyMaxLength).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
{
IdentityResourcePropertyConsts.ValueMaxLength = 300;
}
b.Property(x => x.Value).HasMaxLength(IdentityResourcePropertyConsts.ValueMaxLength).IsRequired();
});
#endregion
#region ApiResource
builder.Entity<ApiResource>(b =>
{
b.ToTable(options.TablePrefix + "ApiResources", options.Schema);
b.ConfigureByConvention();
b.HasIndex(x => x.Name).IsUnique();
b.Property(x => x.Name).HasMaxLength(ApiResourceConsts.NameMaxLength).IsRequired();
b.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength);
b.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength);
b.Property(x => x.Properties)
.HasConversion(new AbpJsonValueConverter<Dictionary<string, string>>())
.Metadata.SetValueComparer(new AbpDictionaryValueComparer<string, string>());
b.Property(x => x.AllowedAccessTokenSigningAlgorithms).HasMaxLength(ApiResourceConsts.AllowedAccessTokenSigningAlgorithmsMaxLength);
b.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
b.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();
});
builder.Entity<ApiSecret>(b =>
builder.Entity<ApiResourceSecret>(b =>
{
b.ToTable(options.TablePrefix + "ApiSecrets", options.Schema);
b.ToTable(options.TablePrefix + "ApiResourceSecrets", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiResourceId, x.Type, x.Value});
b.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
b.Property(x => x.Type).HasMaxLength(ApiResourceSecretConsts.TypeMaxLength).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
{
SecretConsts.ValueMaxLengthValue = 300;
}
b.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLengthValue).IsRequired();
ApiResourceSecretConsts.ValueMaxLength = 300;
}
b.Property(x => x.Value).HasMaxLength(ApiResourceSecretConsts.ValueMaxLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(ApiResourceSecretConsts.DescriptionMaxLength);
});
builder.Entity<ApiResourceClaim>(b =>
{
b.ToTable(options.TablePrefix + "ApiClaims", options.Schema);
b.ToTable(options.TablePrefix + "ApiResourceClaims", options.Schema);
b.ConfigureByConvention();
@ -281,19 +279,51 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
});
builder.Entity<ApiResourceScope>(b =>
{
b.ToTable(options.TablePrefix + "ApiResourceScopes", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiResourceId, x.Scope});
b.Property(x => x.Scope).HasMaxLength(ApiResourceScopeConsts.ScopeMaxLength).IsRequired();
});
builder.Entity<ApiResourceProperty>(b =>
{
b.ToTable(options.TablePrefix + "ApiResourceProperties", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiResourceId, x.Key, x.Value});
b.Property(x => x.Key).HasMaxLength(ApiResourcePropertyConsts.KeyMaxLength).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
{
ApiResourcePropertyConsts.ValueMaxLength = 300;
}
b.Property(x => x.Value).HasMaxLength(ApiResourcePropertyConsts.ValueMaxLength).IsRequired();
});
#endregion
#region ApiScope
builder.Entity<ApiScope>(b =>
{
b.ToTable(options.TablePrefix + "ApiScopes", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiResourceId, x.Name});
b.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
b.Property(x => x.DisplayName).HasMaxLength(ApiScopeConsts.DisplayNameMaxLength);
b.Property(x => x.Description).HasMaxLength(ApiScopeConsts.DescriptionMaxLength);
b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => new {x.ApiResourceId, x.Name}).IsRequired();
b.HasIndex(x => x.Name).IsUnique();
b.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.ApiScopeId).IsRequired();
b.HasMany(x => x.Properties).WithOne().HasForeignKey(x => x.ApiScopeId).IsRequired();
});
builder.Entity<ApiScopeClaim>(b =>
@ -302,29 +332,90 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiResourceId, x.Name, x.Type});
b.HasKey(x => new {x.ApiScopeId, x.Type});
b.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired();
b.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired();
});
builder.Entity<ApiScopeProperty>(b =>
{
b.ToTable(options.TablePrefix + "ApiScopeProperties", options.Schema);
b.ConfigureByConvention();
b.HasKey(x => new {x.ApiScopeId, x.Key, x.Value});
b.Property(x => x.Key).HasMaxLength(ApiScopePropertyConsts.KeyMaxLength).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql, EfCoreDatabaseProvider.Oracle))
{
ApiScopePropertyConsts.ValueMaxLength = 300;
}
b.Property(x => x.Value).HasMaxLength(ApiScopePropertyConsts.ValueMaxLength).IsRequired();
});
#endregion
#region PersistedGrant
builder.Entity<PersistedGrant>(b =>
{
b.ToTable(options.TablePrefix + "PersistedGrants", options.Schema);
b.ConfigureByConvention();
b.Property(x => x.Key).HasMaxLength(PersistedGrantConsts.KeyMaxLength).ValueGeneratedNever();
b.Property(x => x.Type).HasMaxLength(PersistedGrantConsts.TypeMaxLength).IsRequired();
b.Property(x => x.SubjectId).HasMaxLength(PersistedGrantConsts.SubjectIdMaxLength);
b.Property(x => x.SessionId).HasMaxLength(PersistedGrantConsts.SessionIdMaxLength);
b.Property(x => x.ClientId).HasMaxLength(PersistedGrantConsts.ClientIdMaxLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(PersistedGrantConsts.DescriptionMaxLength);
b.Property(x => x.CreationTime).IsRequired();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
{
PersistedGrantConsts.DataMaxLengthValue = 10000; //TODO: MySQL accepts 20.000. We can consider to change in v3.0.
}
b.Property(x => x.Data).HasMaxLength(PersistedGrantConsts.DataMaxLengthValue).IsRequired();
b.HasKey(x => x.Key); //TODO: What about Id!!!
b.HasIndex(x => new {x.SubjectId, x.ClientId, x.Type});
b.HasIndex(x => new {x.SubjectId, x.SessionId, x.Type});
b.HasIndex(x => x.Expiration);
});
#endregion
#region DeviceFlowCodes
builder.Entity<DeviceFlowCodes>(b =>
{
b.ToTable(options.TablePrefix + "DeviceFlowCodes", options.Schema);
b.ConfigureByConvention();
b.Property(x => x.DeviceCode).HasMaxLength(200).IsRequired();
b.Property(x => x.UserCode).HasMaxLength(200).IsRequired();
b.Property(x => x.SubjectId).HasMaxLength(200);
b.Property(x => x.ClientId).HasMaxLength(200).IsRequired();
b.Property(x => x.DeviceCode).HasMaxLength(DeviceFlowCodesConsts.DeviceCodeMaxLength).IsRequired();
b.Property(x => x.UserCode).HasMaxLength(DeviceFlowCodesConsts.UserCodeMaxLength).IsRequired();
b.Property(x => x.SubjectId).HasMaxLength(DeviceFlowCodesConsts.SubjectIdMaxLength);
b.Property(x => x.SessionId).HasMaxLength(DeviceFlowCodesConsts.SessionIdMaxLength);
b.Property(x => x.ClientId).HasMaxLength(DeviceFlowCodesConsts.ClientIdMaxLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(DeviceFlowCodesConsts.DescriptionMaxLength);
b.Property(x => x.CreationTime).IsRequired();
b.Property(x => x.Expiration).IsRequired();
b.Property(x => x.Data).HasMaxLength(50000).IsRequired();
b.HasIndex(x => new {x.UserCode}).IsUnique();
if (IsDatabaseProvider(builder, options, EfCoreDatabaseProvider.MySql))
{
DeviceFlowCodesConsts.DataMaxLength = 10000; //TODO: MySQL accepts 20.000. We can consider to change in v3.0.
}
b.Property(x => x.Data).HasMaxLength(DeviceFlowCodesConsts.DataMaxLength).IsRequired();
b.HasIndex(x => new {x.UserCode});
b.HasIndex(x => x.DeviceCode).IsUnique();
b.HasIndex(x => x.Expiration);
});
#endregion
}
private static bool IsDatabaseProvider(
@ -344,4 +435,4 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
return false;
}
}
}
}

52
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs

@ -12,19 +12,24 @@ namespace Volo.Abp.IdentityServer.Grants
{
public class PersistentGrantRepository : EfCoreRepository<IIdentityServerDbContext, PersistedGrant, Guid>, IPersistentGrantRepository
{
public PersistentGrantRepository(IDbContextProvider<IIdentityServerDbContext> dbContextProvider)
public PersistentGrantRepository(IDbContextProvider<IIdentityServerDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<List<PersistedGrant>> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await Filter(subjectId, sessionId, clientId, type)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<PersistedGrant> FindByKeyAsync(
string key,
CancellationToken cancellationToken = default)
{
return await DbSet
.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken))
;
return await DbSet.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken));
}
public virtual async Task<List<PersistedGrant>> GetListBySubjectIdAsync(
@ -37,7 +42,7 @@ namespace Volo.Abp.IdentityServer.Grants
}
public virtual async Task<List<PersistedGrant>> GetListByExpirationAsync(
DateTime maxExpirationDate,
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default)
{
@ -48,27 +53,32 @@ namespace Volo.Abp.IdentityServer.Grants
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task DeleteAsync(
string subjectId,
string clientId,
public async Task DeleteAsync(
string subjectId = null,
string sessionId = null,
string clientId = null,
string type = null,
CancellationToken cancellationToken = default)
{
await DeleteAsync(
x => x.SubjectId == subjectId && x.ClientId == clientId,
cancellationToken: GetCancellationToken(cancellationToken)
);
var persistedGrants = await Filter(subjectId, sessionId, clientId, type).ToListAsync(GetCancellationToken(cancellationToken));
foreach (var persistedGrant in persistedGrants)
{
DbSet.Remove(persistedGrant);
}
}
public virtual async Task DeleteAsync(
string subjectId,
string clientId,
string type,
CancellationToken cancellationToken = default)
private IQueryable<PersistedGrant> Filter(
string subjectId,
string sessionId,
string clientId,
string type)
{
await DeleteAsync(
x => x.SubjectId == subjectId && x.ClientId == clientId && x.Type == type,
cancellationToken: GetCancellationToken(cancellationToken)
);
return DbSet
.WhereIf(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId)
.WhereIf(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId)
.WhereIf(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId)
.WhereIf(!type.IsNullOrWhiteSpace(), x => x.Type == type);
}
}
}

4
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -19,7 +19,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources
}
public virtual async Task<List<IdentityResource>> GetListByScopesAsync(
public virtual async Task<List<IdentityResource>> GetListByScopeNameAsync(
string[] scopeNames,
bool includeDetails = false,
CancellationToken cancellationToken = default)

5
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs

@ -1,11 +1,12 @@
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.MongoDB;
using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource;
namespace Volo.Abp.IdentityServer.MongoDB
{
@ -14,6 +15,8 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
public IMongoCollection<ApiResource> ApiResources => Collection<ApiResource>();
public IMongoCollection<ApiScope> ApiScopes => Collection<ApiScope>();
public IMongoCollection<Client> Clients => Collection<Client>();
public IMongoCollection<IdentityResource> IdentityResources => Collection<IdentityResource>();

11
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs

@ -1,5 +1,6 @@
using System;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
@ -27,15 +28,21 @@ namespace Volo.Abp.IdentityServer.MongoDB
b.CollectionName = options.CollectionPrefix + "ApiResources";
});
builder.Entity<Client>(b =>
builder.Entity<ApiScope>(b =>
{
b.CollectionName = options.CollectionPrefix + "Clients";
b.CollectionName = options.CollectionPrefix + "ApiScopes";
});
builder.Entity<IdentityResource>(b =>
{
b.CollectionName = options.CollectionPrefix + "IdentityResources";
});
builder.Entity<Client>(b =>
{
b.CollectionName = options.CollectionPrefix + "Clients";
});
builder.Entity<PersistedGrant>(b =>
{
b.CollectionName = options.CollectionPrefix + "PersistedGrants";

8
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs

@ -1,11 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource;
using Client = Volo.Abp.IdentityServer.Clients.Client;
using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource;
namespace Volo.Abp.IdentityServer.MongoDB
{
@ -30,6 +31,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
context.Services.AddMongoDbContext<AbpIdentityServerMongoDbContext>(options =>
{
options.AddRepository<ApiResource, MongoApiResourceRepository>();
options.AddRepository<ApiScope, MongoApiScopeRepository>();
options.AddRepository<IdentityResource, MongoIdentityResourceRepository>();
options.AddRepository<Client, MongoClientRepository>();
options.AddRepository<PersistedGrant, MongoPersistentGrantRepository>();

5
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs

@ -1,11 +1,12 @@
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.MongoDB;
using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource;
namespace Volo.Abp.IdentityServer.MongoDB
{
@ -14,6 +15,8 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
IMongoCollection<ApiResource> ApiResources { get; }
IMongoCollection<ApiScope> ApiScopes { get; }
IMongoCollection<Client> Clients { get; }
IMongoCollection<IdentityResource> IdentityResources { get; }

19
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs

@ -6,8 +6,9 @@ using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using System.Linq.Dynamic.Core;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.MongoDB;
namespace Volo.Abp.IdentityServer.MongoDB
@ -18,18 +19,26 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
}
public virtual async Task<ApiResource> FindByNameAsync(string name, bool includeDetails = true, CancellationToken cancellationToken = default)
public async Task<ApiResource> FindByNameAsync(string apiResourceName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(ar => ar.Name == name)
.Where(ar => ar.Name == apiResourceName)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<ApiResource>> FindByNameAsync(string[] apiResourceNames, bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(ar => apiResourceNames.Contains(ar.Name))
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<ApiResource>> GetListByScopesAsync(string[] scopeNames, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(ar => ar.Scopes.Any(x => scopeNames.Contains(x.Name)))
.Where(ar => ar.Scopes.Any(x => scopeNames.Contains(x.Scope)))
.ToListAsync(GetCancellationToken(cancellationToken));
}
@ -54,7 +63,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
public virtual async Task<bool> CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken);
return await GetMongoQueryable().AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken));
}
}
}

57
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.IdentityServer.ApiScopes;
using System.Linq.Dynamic.Core;
using Volo.Abp.MongoDB;
namespace Volo.Abp.IdentityServer.MongoDB
{
public class MongoApiScopeRepository : MongoDbRepository<IAbpIdentityServerMongoDbContext, ApiScope, Guid>,
IApiScopeRepository
{
public MongoApiScopeRepository(IMongoDbContextProvider<IAbpIdentityServerMongoDbContext> dbContextProvider) :
base(dbContextProvider)
{
}
public async Task<ApiScope> GetByNameAsync(string scopeName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().FirstOrDefaultAsync(x => x.Name == scopeName, GetCancellationToken(cancellationToken));
}
public async Task<List<ApiScope>> GetListByNameAsync(string[] scopeNames, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var query = from scope in GetMongoQueryable()
where scopeNames.Contains(scope.Name)
select scope;
return await query.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<ApiScope>> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter = null, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.WhereIf(!filter.IsNullOrWhiteSpace(),
x => x.Name.Contains(filter) ||
x.Description.Contains(filter) ||
x.DisplayName.Contains(filter))
.OrderBy(sorting ?? nameof(ApiScope.Name))
.As<IMongoQueryable<ApiScope>>()
.PageBy<ApiScope, IMongoQueryable<ApiScope>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<bool> CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken));
}
}
}

2
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs

@ -21,7 +21,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
}
public virtual async Task<Client> FindByCliendIdAsync(
public virtual async Task<Client> FindByClientIdAsync(
string clientId,
bool includeDetails = true,
CancellationToken cancellationToken = default)

2
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs

@ -40,7 +40,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<IdentityResource>> GetListByScopesAsync(string[] scopeNames, bool includeDetails = false,
public virtual async Task<List<IdentityResource>> GetListByScopeNameAsync(string[] scopeNames, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()

42
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
@ -8,6 +9,7 @@ using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.MongoDB;
namespace Volo.Abp.IdentityServer.MongoDB
{
public class MongoPersistentGrantRepository : MongoDbRepository<IAbpIdentityServerMongoDbContext, PersistedGrant, Guid>, IPersistentGrantRepository
@ -16,6 +18,13 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
}
public async Task<List<PersistedGrant>> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await Filter(subjectId, sessionId, clientId, type)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<PersistedGrant> FindByKeyAsync(string key, CancellationToken cancellationToken = default)
{
@ -27,8 +36,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
return await GetMongoQueryable()
.Where(x => x.SubjectId == subjectId)
.ToListAsync(GetCancellationToken(cancellationToken))
;
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<PersistedGrant>> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount,
@ -41,6 +49,22 @@ namespace Volo.Abp.IdentityServer.MongoDB
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task DeleteAsync(
string subjectId = null,
string sessionId = null,
string clientId = null,
string type = null,
CancellationToken cancellationToken = default)
{
var persistedGrants = await Filter(subjectId, sessionId, clientId, type)
.ToListAsync(GetCancellationToken(cancellationToken));
foreach (var persistedGrant in persistedGrants)
{
await DeleteAsync(persistedGrant, false, GetCancellationToken(cancellationToken));
}
}
public virtual async Task DeleteAsync(string subjectId, string clientId, CancellationToken cancellationToken = default)
{
await DeleteAsync(
@ -56,5 +80,19 @@ namespace Volo.Abp.IdentityServer.MongoDB
cancellationToken: GetCancellationToken(cancellationToken)
);
}
private IMongoQueryable<PersistedGrant> Filter(
string subjectId,
string sessionId,
string clientId,
string type)
{
return GetMongoQueryable()
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId)
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId)
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId)
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!type.IsNullOrWhiteSpace(), x => x.Type == type)
.As<IMongoQueryable<PersistedGrant>>();
}
}
}

2
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs

@ -33,7 +33,7 @@ namespace Volo.Abp.IdentityServer.Clients
client.ClientId.ShouldBe("42");
client.ProtocolType.ShouldBe("TestProtocol-42");
client.AllowedCorsOrigins.ShouldContain("Origin1");
client.AllowedScopes.ShouldContain("api1");
client.AllowedScopes.ShouldContain("Test-ApiScope-Name-1");
}
}
}

25
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs

@ -19,20 +19,20 @@ namespace Volo.Abp.IdentityServer.Clients
}
[Fact]
public async Task FindApiResourceAsync_Should_Return_Null_If_Not_Found()
public async Task FindApiResourceAsync_Should_Return_Empty_If_Not_Found()
{
//Act
var resource = await _resourceStore.FindApiResourceAsync("non-existing-name");
var resource = await _resourceStore.FindApiResourcesByNameAsync(new []{"non-existing-name"});
//Assert
resource.ShouldBeNull();
resource.ShouldBeEmpty();
}
[Fact]
public async Task FindApiResourceAsync_Should_Return_If_Found()
{
//Act
var apiResource = await _resourceStore.FindApiResourceAsync("Test-ApiResource-Name-1");
var apiResource = (await _resourceStore.FindApiResourcesByNameAsync(new []{"Test-ApiResource-Name-1"})).FirstOrDefault();
//Assert
apiResource.ShouldNotBe(null);
@ -45,7 +45,7 @@ namespace Volo.Abp.IdentityServer.Clients
public async Task FindApiResourcesByScopeAsync_Should_Return_If_Found()
{
//Act
var apiResources = (await _resourceStore.FindApiResourcesByScopeAsync(new List<string>
var apiResources = (await _resourceStore.FindApiResourcesByScopeNameAsync(new List<string>
{
"Test-ApiResource-ApiScope-Name-1"
})).ToList();
@ -53,24 +53,23 @@ namespace Volo.Abp.IdentityServer.Clients
//Assert
apiResources.ShouldNotBe(null);
apiResources[0].Scopes.Count.ShouldBe(2);
apiResources[0].Scopes.Count.ShouldBe(3);
}
[Fact]
public async Task FindIdentityResourcesByScopeAsync_Should_Return_For_Given_Scopes()
{
//Act
var identityResourcesByScope = await _resourceStore.FindIdentityResourcesByScopeAsync(new List<string>
var identityResourcesByScope = (await _resourceStore.FindIdentityResourcesByScopeNameAsync(new List<string>
{
"Test-Identity-Resource-Name-1"
});
})).ToArray();
//Assert
var resourcesByScope = identityResourcesByScope as IdentityResource[] ?? identityResourcesByScope.ToArray();
resourcesByScope.Length.ShouldBe(1);
resourcesByScope.First().DisplayName.ShouldBe("Test-Identity-Resource-DisplayName-1");
resourcesByScope.First().Description.ShouldBe("Test-Identity-Resource-Description-1");
resourcesByScope.First().Required.ShouldBe(true);
identityResourcesByScope.Length.ShouldBe(1);
identityResourcesByScope.First().DisplayName.ShouldBe("Test-Identity-Resource-DisplayName-1");
identityResourcesByScope.First().Description.ShouldBe("Test-Identity-Resource-Description-1");
identityResourcesByScope.First().Required.ShouldBe(true);
}
[Fact]

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save