Browse Source

Merge pull request #15843 from abpframework/auto-merge/rel-7-0/1765

Merge branch rel-7.1 with rel-7.0
pull/15849/head
maliming 4 years ago
committed by GitHub
parent
commit
a95138b057
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 230
      docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md
  2. 6
      docs/en/Modules/IdentityServer.md
  3. 20
      docs/en/docs-nav.json
  4. 5
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyOptions.cs
  5. 26
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests.cs
  6. 3
      npm/ng-packs/package.json
  7. 10
      npm/ng-packs/packages/core/src/lib/abstracts/auth-response.model.ts
  8. 19
      npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts
  9. 1
      npm/ng-packs/packages/core/src/lib/abstracts/index.ts
  10. 31
      npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts
  11. 45
      npm/ng-packs/scripts/copy-packages-to-templates.ts

230
docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md

@ -0,0 +1,230 @@
# Migrating from OpenIddict to IdentityServer4 Step by Step Guide
ABP startup templates use `OpenIddict` OpenID provider from v6.0.0 by default and `IdentityServer` projects are renamed to `AuthServer` in tiered/separated solutions. Since OpenIddict is the default OpenID provider library for ABP templates since v6.0, you may want to keep using [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) library, even it is **archived and no longer maintained by the owners**. ABP doesn't provide support for newer versions of IdentityServer. This guide provides layer-by-layer guidance for migrating your existing [OpenIddict](https://github.com/openiddict/openiddict-core) application to IdentityServer4.
## IdentityServer4 Migration Steps
Use the `abp update` command to update your existing application. See [Upgrading docs](../Upgrading.md) for more info. Apply required migrations by following the [Migration Guides](Index.md) based on your application version.
### Domain.Shared Layer
- In **MyApplication.Domain.Shared.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.Domain.Shared" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.Domain.Shared" Version="6.0.*" />
```
- In **MyApplicationDomainSharedModule.cs** replace usings and **module dependencies:**
```csharp
using Volo.Abp.OpenIddict;
...
typeof(AbpOpenIddictDomainSharedModule)
```
with
```csharp
using Volo.Abp.IdentityServer;
...
typeof(AbpIdentityServerDomainSharedModule)
```
### Domain Layer
- In **MyApplication.Domain.csproj** replace **project references**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.Domain" Version="6.0.*" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.OpenIddict" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="6.0.*" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.IdentityServer" Version="6.0.*" />
```
- In **MyApplicationDomainModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict;
using Volo.Abp.PermissionManagement.OpenIddict;
...
typeof(AbpOpenIddictDomainModule),
typeof(AbpPermissionManagementDomainOpenIddictModule),
```
with
```csharp
using Volo.Abp.IdentityServer;
using Volo.Abp.PermissionManagement.IdentityServer;
...
typeof(AbpIdentityServerDomainModule),
typeof(AbpPermissionManagementDomainIdentityServerModule),
```
#### OpenIddictDataSeedContributor
DataSeeder is the most important part for starting the application since it seeds the initial data for both OpenID providers.
- Create a folder named *IdentityServer* under the Domain project and copy the [IdentityServerDataSeedContributor.cs](https://github.com/abpframework/abp-samples/blob/master/Ids2OpenId/src/Ids2OpenId.Domain/IdentityServer/IdentityServerDataSeedContributor.cs) under this folder. **Rename** all the `OpenId2Ids` with your project name.
- Delete *OpenIddict* folder that contains `OpenIddictDataSeedContributor.cs` which is no longer needed.
### EntityFrameworkCore Layer
If you are using MongoDB, skip this step and check the *MongoDB* layer section.
- In **MyApplication.EntityFrameworkCore.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.EntityFrameworkCore" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.EntityFrameworkCore" Version="6.0.*" />
```
- In **MyApplicationEntityFrameworkCoreModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
typeof(AbpOpenIddictEntityFrameworkCoreModule),
```
with
```csharp
using Volo.Abp.IdentityServer.EntityFrameworkCore;
...
typeof(AbpIdentityServerEntityFrameworkCoreModule),
```
- In **MyApplicationDbContext.cs** replace usings and **fluent api configurations**:
```csharp
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
...
builder.ConfigureOpenIddict();
```
with
```csharp
using Volo.Abp.IdentityServer.EntityFrameworkCore;
...
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
...
builder.ConfigureIdentityServer();
```
> Not: You need to create new migration after updating the fluent api. Navigate to *EntityFrameworkCore* folder and add a new migration. Ex, `dotnet ef migrations add Updated_To_IdentityServer `
### MongoDB Layer
If you are using EntityFrameworkCore, skip this step and check the *EntityFrameworkCore* layer section.
- In **MyApplication.MongoDB.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.MongoDB" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.MongoDB" Version="6.0.*" />
```
- In **MyApplicationMongoDbModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict.MongoDB;
...
typeof(AbpOpenIddictMongoDbModule),
```
with
```csharp
using Volo.Abp.IdentityServer.MongoDB;
...
typeof(AbpIdentityServerMongoDbModule),
```
### DbMigrator Project
- In `appsettings.json` **replace OpenIddict section with IdentityServer** since IdentityServerDataSeeder will be using these information for initial data seeding:
```json
"IdentityServer": { // Rename OpenIddict to IdentityServer
"Clients ": { // Rename Applications to Clients
...
}
}
```
### Test Project
- In **MyApplicationTestBaseModule.cs** **add** the IdentityServer related using and PreConfigurations:
```csharp
using Volo.Abp.IdentityServer;
```
and
```csharp
PreConfigure<AbpIdentityServerBuilderOptions>(options =>
{
options.AddDeveloperSigningCredential = false;
});
PreConfigure<IIdentityServerBuilder>(identityServerBuilder =>
{
identityServerBuilder.AddDeveloperSigningCredential(false, System.Guid.NewGuid().ToString());
});
```
to `PreConfigureServices` to run authentication related unit tests.
### UI Layer
You can follow the migrations guides from IdentityServer to OpenIddict in **reverse order** to update your UIs. You can also check the source-code for [Index.cshtml.cs](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml) and [Index.cshtml](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml.cs) files for **AuthServer** project.
- [Angular UI Migration](OpenIddict-Angular.md)
- [MVC/Razor UI Migration](OpenIddict-Mvc.md)
- [Blazor-Server UI Migration](OpenIddict-Blazor-Server.md)
- [Blazor-Wasm UI Migration](OpenIddict-Blazor.md)
## Source code of samples and module
* [Open source tiered & separate auth server application migrate OpenIddict to Identity Server](https://github.com/abpframework/abp-samples/tree/master/OpenId2Ids)
* [IdentityServer module document](https://docs.abp.io/en/abp/6.0/Modules/IdentityServer)
* [IdentityServer module source code](https://github.com/abpframework/abp/tree/rel-6.0/modules/identityserver)

6
docs/en/Modules/IdentityServer.md

@ -1,10 +1,12 @@
# IdentityServer Module
IdentityServer module provides a full integration with the [IdentityServer](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database.
IdentityServer module provides a full integration with the [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database. **This module is replaced by** [OpenIddict module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict) after ABP v6.0 in the startup templates.
> Note: You can not use IdentityServer and OpenIddict modules together. They are separate OpenID provider libraries for the same job.
## How to Install
This module comes as pre-installed (as NuGet/NPM packages). You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module.
You don't need this module when you are using OpenIddict module. However, if you want to keep using IdentityServer4 for your applications, you can install this module and remove the OpenIddict module. You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module.
### The Source Code

20
docs/en/docs-nav.json

@ -1370,16 +1370,22 @@
},
{
"text": "IdentityServer",
"path": "Modules/IdentityServer.md"
"path": "Modules/IdentityServer.md",
"items": [
{
"text": "IdentityServer Migration Guide",
"path": "Migration-Guides/IdentityServer4-Step-by-Step.md"
}
]
},
{
"text": "OpenIddict",
"items": [
{
"text": "OpenIddict Migration Guide",
"path": "Migration-Guides/OpenIddict-Step-by-Step.md"
}
],
"items": [
{
"text": "OpenIddict Migration Guide",
"path": "Migration-Guides/OpenIddict-Step-by-Step.md"
}
],
"path": "Modules/OpenIddict.md"
},
{

5
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyOptions.cs

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Net;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
@ -42,8 +43,8 @@ public class AbpAspNetCoreMultiTenancyOptions
var message = exception.Message;
var details = exception is BusinessException businessException ? businessException.Details : string.Empty;
await context.Response.WriteAsync($"<html lang=\"{CultureInfo.CurrentCulture.Name}\"><body>\r\n");
await context.Response.WriteAsync($"<h3>{message}</h3>{details}<br>\r\n");
await context.Response.WriteAsync($"<html lang=\"{HtmlEncoder.Default.Encode(CultureInfo.CurrentCulture.Name)}\"><body>\r\n");
await context.Response.WriteAsync($"<h3>{HtmlEncoder.Default.Encode(message)}</h3>{HtmlEncoder.Default.Encode(details)}<br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
// Note the 500 spaces are to work around an IE 'feature'

26
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests.cs

@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Shouldly;
using Xunit;
namespace Volo.Abp.AspNetCore.MultiTenancy;
public class AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests : AspNetCoreMultiTenancyTestBase
{
private readonly AbpAspNetCoreMultiTenancyOptions _options;
public AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests()
{
_options = ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreMultiTenancyOptions>>().Value;
}
[Fact]
public async Task MultiTenancyMiddlewareErrorPageBuilder()
{
var result = await GetResponseAsStringAsync($"http://abp.io?{_options.TenantKey}=<script>alert(hi)</script>", HttpStatusCode.NotFound);
result.ShouldNotContain("<script>alert(hi)</script>");
}
}

3
npm/ng-packs/package.json

@ -38,7 +38,8 @@
"debug:schematics-dist": "./node_modules/.bin/ng g ./dist/packages/schematics/collection.json:proxy-add --module __default --apiName __default --source __default --target __default --url http://localhost:4300 --service-type application",
"ci": "yarn affected:lint && yarn affected:build && yarn affected:test",
"lerna": "lerna",
"migrate-nx": "yarn nx migrate --run-migrations"
"migrate-nx": "yarn nx migrate --run-migrations",
"copy-to:app": "cd scripts && yarn && yarn copy-to-templates -t app"
},
"private": true,
"devDependencies": {

10
npm/ng-packs/packages/core/src/lib/abstracts/auth-response.model.ts

@ -0,0 +1,10 @@
export interface AbpAuthResponse {
access_token: string;
id_token: string;
token_type: string;
expires_in: number;
refresh_token: string;
scope: string;
state?: string;
tenant_domain?: string;
}

19
npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts

@ -1,7 +1,9 @@
import { HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { Observable, of } from 'rxjs';
import { LoginParams } from '../models/auth';
import { AbpAuthResponse } from './auth-response.model';
/**
* Abstract service for Authentication.
@ -10,8 +12,6 @@ import { LoginParams } from '../models/auth';
providedIn: 'root',
})
export class AuthService implements IAuthService {
constructor() {}
private warningMessage() {
console.error('You should add @abp/ng-oauth packages or create your own auth packages.');
}
@ -42,6 +42,15 @@ export class AuthService implements IAuthService {
this.warningMessage();
return false;
}
loginUsingGrant(
grantType: string,
parameters: object,
headers?: HttpHeaders,
): Promise<AbpAuthResponse> {
console.log({ grantType, parameters, headers });
return Promise.reject(new Error('not implemented'));
}
}
export interface IAuthService {
@ -56,4 +65,10 @@ export interface IAuthService {
navigateToLogin(queryParams?: Params): void;
login(params: LoginParams): Observable<any>;
loginUsingGrant(
grantType: string,
parameters: object,
headers?: HttpHeaders,
): Promise<AbpAuthResponse>;
}

1
npm/ng-packs/packages/core/src/lib/abstracts/index.ts

@ -1,3 +1,4 @@
export * from './ng-model.component';
export * from './auth.guard';
export * from './auth.service';
export * from './auth-response.model';

31
npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts

@ -2,23 +2,27 @@ import { Injectable, Injector } from '@angular/core';
import { Params } from '@angular/router';
import { from, Observable, lastValueFrom } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import { IAuthService, LoginParams } from '@abp/ng.core';
import { AbpAuthResponse, IAuthService, LoginParams } from '@abp/ng.core';
import { AuthFlowStrategy } from '../strategies';
import { EnvironmentService } from '@abp/ng.core';
import { AUTH_FLOW_STRATEGY } from '../tokens/auth-flow-strategy';
import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
import { OAuthService } from 'angular-oauth2-oidc';
import { HttpHeaders } from '@angular/common/http';
@Injectable({
providedIn: 'root',
})
export class AbpOAuthService implements IAuthService {
private strategy!: AuthFlowStrategy;
private readonly oAuthService: OAuthService;
get isInternalAuth() {
return this.strategy.isInternalAuth;
}
constructor(protected injector: Injector, private oAuthService: OAuthService) {}
constructor(protected injector: Injector) {
this.oAuthService = this.injector.get(OAuthService);
}
async init() {
const environmentService = this.injector.get(EnvironmentService);
@ -54,4 +58,25 @@ export class AbpOAuthService implements IAuthService {
get isAuthenticated(): boolean {
return this.oAuthService.hasValidAccessToken();
}
loginUsingGrant(
grantType: string,
parameters: object,
headers?: HttpHeaders,
): Promise<AbpAuthResponse> {
const { clientId: client_id, dummyClientSecret: client_secret } = this.oAuthService;
const access_token = this.oAuthService.getAccessToken();
const p = {
access_token,
grant_type: grantType,
client_id,
...parameters,
};
if (client_secret) {
p['client_secret'] = client_secret;
}
return this.oAuthService.fetchTokenUsingGrant(grantType, p, headers);
}
}

45
npm/ng-packs/scripts/copy-packages-to-templates.ts

@ -1,7 +1,7 @@
import execa from 'execa';
import fse from 'fs-extra';
import fs from 'fs';
import program from 'commander';
import execa from "execa";
import fse from "fs-extra";
import fs from "fs";
import program from "commander";
const defaultTemplates = ['app', 'app-nolayers', 'module'];
const defaultTemplatePath = '../../../templates';
@ -17,21 +17,32 @@ const packageMap = {
'tenant-management': 'ng.tenant-management',
'theme-basic': 'ng.theme.basic',
'theme-shared': 'ng.theme.shared',
'schematics':'ng.schematics',
oauth:'ng.oauth'
schematics: 'ng.schematics',
oauth: 'ng.oauth',
};
program.option('-t, --templates <templates>', 'template dirs', false);
program.option('-p, --template-path <templatePath>', 'root template path', false);
program.option(
'-e, --use-existing-build <useExistingBuild>',
"don't build packages if dist folder exists",
false,
);
program.option('-i, --noInstall', 'skip package installation', false);
program.option('-a, --absolute-dir <absoluteDir>', 'Absolute angular directory', false);
program.parse(process.argv);
const templates = program.templates ? program.templates.split(',') : defaultTemplates;
const templateRootPath = program.templatePath ? program.templatePath : defaultTemplatePath;
(async () => {
await execa('yarn', ['build:all'], {
stdout: 'inherit',
cwd:'../'
});
if (!program.useExistingBuild) {
await execa('yarn', ['build:all'], {
stdout: 'inherit',
cwd: '../',
});
}
await installPackages();
if (!program.noInstall) {
await installPackages();
}
await removeAbpPackages();
@ -41,11 +52,17 @@ const templateRootPath = program.templatePath ? program.templatePath : defaultTe
async function runEachTemplate(
handler: (template: string, templatePath?: string) => void | Promise<any>,
) {
for (var template of templates) {
const templatePath = `${templateRootPath}/${template}/angular`;
const result = handler(template, templatePath);
if (program.absoluteDir) {
const result = handler('', program.absoluteDir);
result instanceof Promise ? await result : result;
} else {
for (var template of templates) {
const templatePath = `${templateRootPath}/${template}/angular`;
const result = handler(template, templatePath);
result instanceof Promise ? await result : result;
}
}
}
async function installPackages() {

Loading…
Cancel
Save