- Only security aspects will be discussed and implemented.
- In this article we will launch apps
- open
tstappWebHostModule.cs-file of the rupbes.tstapp.Web.Host.csproj-project
- right before
context.Services.AddAuthentication(options =>...-line add the code as below:
Click to show the code
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
configuration["AuthServer:MetaAddress"],
new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever());
var discoveryDocument = Task.Run(async () => await configurationManager.GetConfigurationAsync()).Result;
var signingKeys = discoveryDocument.SigningKeys;
- modify
.AddAbpOpenIdConnect("oidc", options => ...)-method call as follows:
Click to show the code
.AddAbpOpenIdConnect("oidc", options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata");
options.ResponseType = OpenIdConnectResponseType.Code;
options.ClientId = configuration["AuthServer:ClientId"];
options.ClientSecret = configuration["AuthServer:ClientSecret"]; // added
// BEGIN =="OR"==
// OR IssuerSigningKeys
options.TokenValidationParameters.IssuerSigningKeys = signingKeys;
// OR MetadataAddress
// options.MetadataAddress = configuration["AuthServer:MetaAddress"]; // added
// END =="OR"==
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.ValidateIssuerSigningKey = true;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("roles"); // for roles
options.Scope.Add("email");
options.Scope.Add("phone");
options.Scope.Add("tstapihost_scope"); // for audience
options.Scope.Add("tstauth_scope"); // for audience
options.Scope.Add("tenantid"); // for tenantid
options.Scope.Add("tstwebapp_scope"); // do not required
/* START: temporarily lines added */
/* for getting debug into about returned access_token and AuthenticationFailed */
/* In production this lines must be deleted */
options.Events ??= new OpenIdConnectEvents();
options.Events.OnAuthenticationFailed = (context) =>
{
return Task.CompletedTask;
};
options.Events.OnTokenValidated = (context) =>
{
return Task.CompletedTask;
};
/* END: temporarily lines added */
// options.ClaimActions.MapUniqueJsonKey()
});
- start
cmd.exe and run the commands
d:
cd D:\Development\rupbes.tstapp\host\rupbes.tstapp.Auth.Host
dotnet ef migrations add Initial
dotnet ef database update
cd D:\Development\rupbes.tstapp\host\rupbes.tstapp.HttpApi.Host
dotnet ef migrations add Initial
dotnet ef database update
- run
rupbes.tstapp.Auth.Host-app. It will create tstadmin-user
- run
rupbes.tstapp.Web.Host-app (do not stop rupbes.tstapp.Auth.Host-app)
- login as
tstadmin-user and password that was defined in keycloak (you can redefine password in keycloak for tstadmin-user. It must be different from 1q2w3E* for correct testing)
- make sure the
Administration menu is available (Users, Roles, Settings, Tenants, Permissions)
- In
rupbes.tstapp.Web.Host-app add tenant with a name tenant001
- In Keycloak create
tstadmin001 user with tenantid=tenant001 and repeat all the steps as for tstadmin-user
- Add
Admin-role for tstadmin001 user
- Goto application database and copy ID of the
tenant001
- modify the code
await seeder.SeedAsync(
new DataSeedContext()
.WithProperty("AdminId", new Guid("00000000-0000-0000-0000-000000000000")) // replace with Keycloak ID of `tstadmin001` user
.WithProperty("AdminEmail", "[email protected]")
.WithProperty("AdminUserName", "tstadmin001")
// .WithProperty("AdminPassword", "1q2w3E*")
);
- do not forget to temporarily change the method
public Task SeedAsync(DataSeedContext context)
{
return IdentityDataSeeder.SeedAsync(
context?[AdminEmailPropertyName] as string ?? AdminEmailDefaultValue,
context?[AdminPasswordPropertyName] as string ?? AdminPasswordDefaultValue,
context?[AdminIdPropertyName] as Guid?,
new Guid("00000000-0000-0000-0000-000000000000") // replace with ID of the `tenant001` // context?.TenantId,
context?[AdminUserNamePropertyName] as string ?? AdminUserNameDefaultValue
);
}
- After logging in as user
tstadmin001 you will see that the Administration menu has changed a little
- for the
rupbes.tstapp.HttpApi.Host-project we have to implement ClaimsTransformation and TenantResolver
- If you plane to use only RBAC (Role-based access control) you do not need to register any users in the APB application. To start the application, it is enough to create the
Admin-role (without a user) in the CustomIdentityDataSeeder class.
Click to show the code
[UnitOfWork]
public virtual async Task<IdentityDataSeedResult> SeedAsync(
[NotNull] string adminEmail,
[NotNull] string adminPassword,
Guid? adminId,
Guid? tenantId = null,
string? adminUserName = null)
{
Check.NotNullOrWhiteSpace(adminEmail, nameof(adminEmail));
Check.NotNullOrWhiteSpace(adminPassword, nameof(adminPassword));
using (CurrentTenant.Change(tenantId))
{
await IdentityOptions.SetAsync();
var result = new IdentityDataSeedResult();
/*
//"admin" user
if (adminUserName.IsNullOrWhiteSpace())
{
adminUserName = IdentityDataSeedContributor.AdminUserNameDefaultValue;
}
var adminUser = await UserRepository.FindByNormalizedUserNameAsync(
LookupNormalizer.NormalizeName(adminUserName)
);
if (adminUser != null)
{
return result;
}
var adminIdEx =
adminId.HasValue
?
((adminId.Value == Guid.Empty) ? GuidGenerator.Create() : adminId.Value)
:
GuidGenerator.Create();
adminUser = new IdentityUser(
adminIdEx,
adminUserName,
adminEmail,
tenantId
)
{
Name = adminUserName
};
(await UserManager.CreateAsync(adminUser, adminPassword, validatePassword: false)).CheckErrors();
*/
result.CreatedAdminUser = true;
//"admin" role
const string adminRoleName = "admin";
var adminRole =
await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName));
if (adminRole == null)
{
adminRole = new IdentityRole(
GuidGenerator.Create(),
adminRoleName,
tenantId
)
{
IsStatic = true,
IsPublic = true
};
(await RoleManager.CreateAsync(adminRole)).CheckErrors();
result.CreatedAdminRole = true;
}
/*
(await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors();
*/
return result;
}
}
- But if you plan to assign permissions directly to the user you need to register users in Abp application.
-
Add User-page of the the application should be rewritten so that the user ID is editable
-
Add New Tenant-page of the the application should be rewritten so that the ID of admin user is editable