https://github.com/abpframework/abp-samples/tree/master/ConcurrentLogin
But this sample is integrated with the identity server 4 and the microservice template has OpenID configuration.
I am trying to integrate concurrent login in the Identity service but the problem is I have version 6.0rc.5 with OpenIdDict integration and the concurrent login sample version is 6.0rc.2 with Identity server 4 integration.
I am struggling to replace the below file to convert into OpenIdDict.
using System;
using System.Threading.Tasks;
using IdentityServer4.AspNetIdentity;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.AspNetIdentity;
using Volo.Abp.IdentityServer.Localization;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace ChurchPharmacy.IdentityService.AspNetIdentity;
public class ConcurrentLoginResourceOwnerPasswordValidator : AbpResourceOwnerPasswordValidator
{
public ConcurrentLoginResourceOwnerPasswordValidator(
Microsoft.AspNetCore.Identity.UserManager<IdentityUser> userManager,
Microsoft.AspNetCore.Identity.SignInManager<IdentityUser> signInManager,
IdentitySecurityLogManager identitySecurityLogManager,
ILogger<ResourceOwnerPasswordValidator<IdentityUser>> logger,
IStringLocalizer<AbpIdentityServerResource> localizer, IOptions<AbpIdentityOptions> abpIdentityOptions,
IHybridServiceScopeFactory serviceScopeFactory, IOptions<IdentityOptions> identityOptions) : base(userManager,
signInManager, identitySecurityLogManager, logger, localizer, abpIdentityOptions, serviceScopeFactory,
identityOptions)
{
}
protected override async Task SetSuccessResultAsync(ResourceOwnerPasswordValidationContext context, IdentityUser user)
{
user.SetProperty(ConcurrentLoginConsts.ConcurrentLoginToken, Guid.NewGuid().ToString("N"));
await UserManager.UpdateAsync(user);
await base.SetSuccessResultAsync(context, user);
}
}
I fixed the issue. I registered a domain resolver on the gateway level. I removed from gateway and registered in administration microservice level.
I have created my custom domain tenant resolver class. I have the below configuration in a microservice architecture. I am using the 6.0 preview version.
Angular Host Domain: abp.mydomain.com Gateway domain: abpapi.mydomain.com AuthServer domain: abpauth.mydomain.com
Tenant domain: tenant.mydomain.com The gateway and auth server are the same as above.
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Clear();
options.TenantResolvers.Add(new TenantDomainResolver("{0}.mydomain.com"));
});
Tenant Domain Resolver
public class TenantDomainResolver: TenantResolveContributorBase
{
public const string ContributorName = "Custom";
public override string Name => ContributorName;
private static readonly string[] ProtocolPrefixes = { "http://", "https://" };
private readonly string _domainFormat;
public TenantDomainResolver(string domainFormat)
{
_domainFormat = domainFormat;
}
public override async Task ResolveAsync(ITenantResolveContext context)
{
var httpContext = context.GetHttpContext();
var referer = httpContext.Request.Headers["Referer"].ToString();
if (string.IsNullOrEmpty(referer))
{
return;
}
referer = referer.RemovePreFix(ProtocolPrefixes);
var extractResult = FormattedStringValueExtracter.Extract(referer, _domainFormat, ignoreCase: true);
if (extractResult != null && extractResult.IsMatch)
{
if (extractResult.Matches[0].Value != "abp") // if referer is not host domain
{
context.Handled = true;
context.TenantIdOrName = extractResult.Matches[0].Value;
}
}
}
It's working fine as the host domain 'abp.mydomain.com' from the angular application but when I browse by the 'tenant.mydomain.com' angular application, its calls API 'https://abpapi.mydomain.com/api/abp/multi-tenancy/tenants/by-name/tenant' and throwing an exception as below.
There is no tenant with the tenant id or name: tenant
but when I copy the endpoint URL and directly call in the browser, it's showing the tenant data.
{"success":true,"tenantId":"40cd013e-dfb4-e3e7-e205-3a0653710d75","name":"tenant","isActive":true}
These are the logs of web gateway.
2022-09-16 18:24:23.492 +05:30 [INF] Application started. Press Ctrl+C to shut down.
2022-09-16 18:24:23.492 +05:30 [INF] Hosting environment: Production
2022-09-16 18:24:23.492 +05:30 [INF] Content root path: D:\abp\abp6\publish\web
2022-09-16 18:24:23.516 +05:30 [INF] Request starting HTTP/2 OPTIONS https://abpapi.mydomain.com/api/abp/multi-tenancy/tenants/by-name/tenant - -
2022-09-16 18:24:23.530 +05:30 [INF] CORS policy execution successful.
2022-09-16 18:24:23.541 +05:30 [INF] Request starting HTTP/2 GET https://abpapi.mydomain.com/api/abp/multi-tenancy/tenants/by-name/tenant - -
2022-09-16 18:24:23.542 +05:30 [INF] CORS policy execution successful.
2022-09-16 18:24:23.547 +05:30 [INF] Request finished HTTP/2 OPTIONS https://abpapi.mydomain.com/api/abp/multi-tenancy/tenants/by-name/tenant - - - 204 - - 31.0747ms
2022-09-16 18:24:23.573 +05:30 [INF] Request finished HTTP/2 GET https://abpapi.mydomain.com/api/abp/multi-tenancy/tenants/by-name/tenant - - - 500 - text/html 31.7616ms
I noticed skipIssuerCheck: true. This will help.
I have one more issue here. Can I have different domains specific tenant configuration as the example below?
sub1.domain.com as host sub2.domain.com as tenant tenant1.com as tenant tenant2.co.uk as tenant tenant3.net as tenant
because the tenant may have their own domain instead of the sub-domain of the host domain or they may choose a subdomain as well.
Currently, I am facing the issue of login in with the tenant URL.
Getting below error when trying to login with tenant login page.
vendor.js:169503 invalid issuer in discovery document expected: https://red.api.getabp.net:44322 current: http://api.getabp.net:44322
Configure<IdentityServerOptions>(options =>
{
options.IssuerUri = configuration["App:SelfUrl"];
});
Anybody is there? Need proper documentation on multi-tenancy domain resolver on microservice architecture
The issue is fixed.
The above issue is fixed. Thanks for your support.
Ok, The issuer issue is fixed. Now getting below error in auth server logs.
[09:37:16 INF] CORS policy execution successful. [09:37:16 INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.TokenEndpoint for /connect/token [09:37:16 INF] {"ClientId": "ChurchPharmacy_Angular", "AuthenticationMethod": "NoSecret", "Category": "Authentication", "Name": "Client Authentication Success", "EventType": "Success", "Id": 1010, "Message": null, "ActivityId": "0HMHUVCU8Q8EE:00000005", "TimeStamp": "2022-05-26T09:37:16.0000000Z", "ProcessId": 1, "LocalIpAddress": "::ffff:10.244.0.167:80", "RemoteIpAddress": "27.109.16.210", "$type": "ClientAuthenticationSuccessEvent"} [09:37:16 ERR] Client not authorized for resource owner flow, check the AllowedGrantTypes setting{"client_id": "ChurchPharmacy_Angular"}, details: {"ClientId": "ChurchPharmacy_Angular", "ClientName": "ChurchPharmacy_Angular", "GrantType": "password", "Scopes": null, "AuthorizationCode": "", "RefreshToken": "", "UserName": null, "AuthenticationContextReferenceClasses": null, "Tenant": null, "IdP": null, "Raw": {"grant_type": "password", "scope": "offline_access openid profile email phone AccountService IdentityService AdministrationService SaasService ProductService", "client_id": "ChurchPharmacy_Angular", "username": "admin", "password": "REDACTED"}, "$type": "TokenRequestValidationLog"} [09:37:16 INF] {"ClientId": "ChurchPharmacy_Angular", "ClientName": "ChurchPharmacy_Angular", "RedirectUri": null, "Endpoint": "Token", "SubjectId": null, "Scopes": null, "GrantType": "password", "Error": "unauthorized_client", "ErrorDescription": null, "Category": "Token", "Name": "Token Issued Failure", "EventType": "Failure", "Id": 2001, "Message": null, "ActivityId": "0HMHUVCU8Q8EE:00000005", "TimeStamp": "2022-05-26T09:37:16.0000000Z", "ProcessId": 1, "LocalIpAddress": "::ffff:10.244.0.167:80", "RemoteIpAddress": "27.109.16.210", "$type": "TokenIssuedFailureEvent"} [09:37:16 INF] Request finished HTTP/1.1 POST http://auth-server-v1.mydomain.com/connect/token application/x-www-form-urlencoded 230 - 400 - application/json;+charset=UTF-8 41.5066ms
I have the below configuration in angular.
const oAuthConfig = {
issuer: 'https://auth-server-v1.mydomain.com',
clientId: 'ChurchPharmacy_Angular',
scope:
'offline_access openid profile email phone AccountService IdentityService AdministrationService SaasService ProductService'
};