Thank you. I will give it a try later on, because requirements have changed. Could you please explain why I cannot reopen another ticket (which I closed) or add answer? When I'm trying to do that, I receive the message saying I am not authorized to do that (I AM logged in).
OK. We implemented service on Angular side and seems like everything works now.
Good, but from ABP-based project's prospective, does it need to be something like this in front-end part: Angular Refresh Token implementation and from back-end part probably nothing needs to be added to make it work?
Hi, could you please make a short test example how to work with refresh_token? In current implementation (built from ABP template) we use only access_token.
Ok, thank you!
@maliming
we have managed to do that by our owns:
BACK-END: implemented & registered custom grant type validator in IdentityServer project:
SwitchToTenantGrantValidator : IdentityServer4.Validation.IExtensionGrantValidator
In short, ValidateAsync accepts the data of authenticated user (his access token, tenant ID, etc.) and makes the decision if the user has to be let in. The method writes data of target tenant into context result object;
FRONT-END: made a call to IdentityServer with the given custom grant type, supplying data required for (1). We used Angular, so I had to extend OAuthService package to support custom grant type request;
Still need to bring everything in order (if (2) was successful) to display correct data in UI: clean old states, etc. - since now old user is still displayed for some reason (despite dispatching new GetAppConfiguration);
The question that is still open: why you hardcoded custom grant type names? When we added manually some custom name to DB - it worked. But in ABP Identity Server management page we cannot do that.
Hi, we can see that meanwhile token lifetime is not prolonged per each request in UI, there is a fixed lifetime that is configured (1 year by default for now, as far as I remember). We want to provide a specific token life, like 15 mins and to prolong token lifetime per each request by this value. How would you recommend to do that?
Could you please make a test project demonstrating how to accomplish our goal? I've spent a lot of time searching for solution on stackoverflow, analyzing ABP code, etc. and I am far behind the schedule. But the solution is still not working.
The pieces of code I have ended up with are the following:
[Authorize]
public async Task<PagedResultDto<LookupDto<string>>> GetTenantsForCurrentUser()
{
if (!CurrentUser.IsAuthenticated)
return null;
var items = await _abxUserRepository.FindTenantsByLoginAsync(CurrentUser.UserName);
return new PagedResultDto<LookupDto<string>>
{
TotalCount = items.Count(),
Items = ObjectMapper.Map<List<Tenant>, List<LookupDto<string>>>(items)
};
}
<div *ngIf="user.isAuthenticated" class="dropdown btn-group" ngbDropdown>
<a
class="btn"
role="button"
id="dropdownMenuTenantsLink"
ngbDropdownToggle
*ngIf="(selectedTenant$ | async)?.name as tenantName"
>
<span>{{ '::Tenants:CurrentTenant' | abpLocalization }}: <b>{{ tenantName }}</b></span>
</a>
<div
ngbDropdownMenu
class="dropdown-menu dropdown-menu-right"
*ngIf="dropdownTenants$ | async"
>
<h6 class="dropdown-header">{{ '::Tenants:SwitchTenant' | abpLocalization }}</h6>
<a
*ngFor="let tenant of dropdownTenants$ | async"
class="dropdown-item pointer"
(click)="switchTenant(user.userName, tenant)"
>
{{ tenant.displayName }}</a
>
</div>
</div>
switchTenant(userName: string, tenant: Common.Lookup<string>) {
this.oAuthService.configure(
this.store.selectSnapshot(ConfigState.getOne('environment')).oAuthConfig,
);
return from(this.oAuthService.loadDiscoveryDocument())
.pipe(
switchMap(() =>
from(
this.oAuthService.fetchTokenUsingGrant(
'Custom', // why we cannot use own name??
null,
new HttpHeaders(
{ ...(tenant.id && { __tenant: tenant.id })}
&& (userName && { user: userName })
)
),
),
),
switchMap(() => this.store.dispatch(new GetAppConfiguration())),
tap(() => {
const redirectUrl =
snq(() => window.history.state.redirectUrl) || (this.options || {}).redirectUrl || '/';
this.store.dispatch(new Navigate([redirectUrl]));
}),
take(1),
).subscribe(() => {});
}
All in all, the idea is:
in app service layer to get the list of all tenants for current user (login name) - see above;
fill dropdown of tenants for passwordless login and supply the tenant id for each entry - see above;
make request from Angular app (using oAuthService->[some passwordless workflow?]) supplying the access token of currently authenticated user, some custom passwordless grant-type and tenant id in order to login (custom extension validator is going to intercept this request on server-side and approve or reject the login).
is the most tricky part, since OAuthService still does not support custom grant type. I've tried to patch the latest angular-oauth2-oidc from github (10.x) and add fetchTokenUsingGrant, but how to update our solution to the patched version? Your framework uses this package inside and I even cannot see angular-oauth2-oidc via npm outdated.
Hi, where I can find information (or better - test examples) how to work with Identity Server in ABP? Generate tokens, use Identity resources, grant types, etc. I saw doc on abp.io, but Identity Server section is very scarse. In fact, I'd like to know what each parameter in Identity Server section in Angular app means and how it is supposed to be used.
Hi,
thank you, would give it a try, but two questions right away:
Change permissions about tenants scope
where this needs to be placed?
public class TenantInfo : AggregateRoot, IMultiTenant
we already use the table for our Tenant
entity (it has Id
and MasterId
for tenant id and master tenant id correspondingly). It also has 1:1 ABP tenant entity:
public class Tenant : SoftDeleteLogEntity<int>
{
...
public int? MasterId { get; set; }
public Tenant MasterTenant { get; set; }
public Guid AbpId { get; set; } // it is ABP tenant's id
public AbpTenant AbpTenant { get; set; } // it is ABP tenant
...
}
public abstract class SoftDeleteLogEntity<TKey> : LogEntity<TKey>, IMayHaveDeleterName, ISoftDelete, IDeletionAuditedObject {...}
public abstract class LogEntity<TKey> : AuditedEntity<TKey>, IMayHaveCreatorName, IMayHaveLastModifierName {...}
but we did not implement IMultiTenant
. Now, when I'd like to do that - I can see TenantId
has to be Guid
, but in our table Id
(MasterId
too, accordingly) is Integer
(it was customer's decision)... How to overcome this problem? Is it OK just to implement a 'fake' Guid
TenantId
field and not use it?