No, i did not insert them manually. I used the code shown previously:
So, after this code I manually run server API request from client which executes the following:
public virtual async Task RefreshAbpPermissionsAsync()
{
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
return;
}
if (_permissionManagementOptions.Value.SaveStaticPermissionsToDatabase)
{
await Policy
.Handle<Exception>()
.WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(RandomHelper.GetRandom((int)Math.Pow(2, retryAttempt) * 8, (int)Math.Pow(2, retryAttempt) * 12)))
.ExecuteAsync(async _ => await _staticPermissionSaver.SaveAsync(), _cancellationTokenProvider.Token);
}
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
return;
}
if (_permissionManagementOptions.Value.IsDynamicPermissionStoreEnabled)
{
await _dynamicPermissionDefinitionStore.GetGroupsAsync();
}
}
This code is successful, as well as StaticPermissionSaver
method RunAsync
. So I see no reasons why the permission assignment afterwards is unsuccessful. No clue.
currentHash
is changed. hasChangesInPermissions
is true
(hasChangesInGroups
is false
).
All in all, the method SaveAsync
works as expected, no catch
triggered... However the permissions are not assigned...
Since I'm doing this from AppService
not AbpModule
as in the original code, I've simplified the code. I took the DI instances of some required services and used the code below (_dynamicPermissionDefinitionStore
is not needed at all I think, because we do not use dynamic permissions, anyway, it makes no difference):
private async Task RefreshAbpStaticAndDynamicPermissionsAsync()
{
await Policy
.Handle<Exception>()
.WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(RandomHelper.GetRandom((int)Math.Pow(2, retryAttempt) * 8, (int)Math.Pow(2, retryAttempt) * 12)))
.ExecuteAsync(async _ => await _staticPermissionSaver.SaveAsync(), _cancellationTokenProvider.Token);
await _dynamicPermissionDefinitionStore.GetGroupsAsync();
}
However, it still does not work.
Do you have any further suggestions?
@maliming
so basically I need to sequentially call SaveStaticPermissionsToDatabaseAsync
and then - PreCacheDynamicPermissionsAsync
?
Not resolved yet
I found out, that the following routing was somehow lost:
{
path: 'identity-server',
loadChildren: () => import('@volo/abp.ng.identity-server').then(m => m.IdentityServerModule.forLazy()),
},
Please, regain my points.
Thank you very much. I will try to improve my implementation using this change. I think I may close the ticket now.
OK - so I abandoned the idea to override the RoutesService
and implemented the following handler (retaining the idea to hide the elements ASAP and unhide them after getting service data) - please have a look if there could be a more efficient solution.
import { ABP, RoutesService } from '@abp/ng.core';
import { Inject, Injectable, OnDestroy } from '@angular/core';
import { BehaviorSubject, ReplaySubject, Subscription, combineLatest } from 'rxjs';
import { distinctUntilChanged, filter, takeLast, takeUntil } from 'rxjs/operators';
import { ModulePermissionsService } from '../services/module-permissions.service';
@Injectable({
providedIn: 'root'
})
export class ModulePermissionHandler implements OnDestroy {
modulePermissionMap$: BehaviorSubject<{[key: string]: string[]}> = new BehaviorSubject<{[key: string]: string[]}>({});
private destroy: ReplaySubject<any> = new ReplaySubject<any>(1);
private stopMenuScan$: ReplaySubject<any> = new ReplaySubject<any>(1);
private mapBindingComplete: boolean = false;
constructor(
private routesService: RoutesService,
private modulePermissionsService: ModulePermissionsService
) {
}
ngOnDestroy(): void {
this.deinit();
}
init() {
this.routesService.flat.filter(x => x.requiredPolicy && (x as any).data?.moduleId).forEach(x => x.invisible = true);
this.routesService.refresh();
combineLatest([this.modulePermissionMap$, this.routesService.flat$])
.pipe
(
filter(result => !this.mapBindingComplete && Object.keys(result[0]).length > 0 && Object.keys(result[1]).length > 0),
takeUntil(this.destroy),
takeUntil(this.stopMenuScan$)
)
.subscribe(([modulePermissionMap, nonLazyLoadedRoute]) => {
let permissionProhibitedPageIds: string[] = [];
nonLazyLoadedRoute.filter(node => node.requiredPolicy).forEach((nonLazyRouteItem: ABP.Route) => {
let moduleId = (nonLazyRouteItem as any).data?.moduleId;
if (moduleId) {
const moduleIdPolicyViolated = !modulePermissionMap[moduleId] || modulePermissionMap[moduleId] && !modulePermissionMap[moduleId].includes(nonLazyRouteItem.requiredPolicy as string);
const ordinaryRolePolicyViolated = !modulePermissionMap['_ordinaryRole'] || modulePermissionMap['_ordinaryRole'] && !modulePermissionMap['_ordinaryRole'].includes(nonLazyRouteItem.requiredPolicy as string);
if (moduleIdPolicyViolated && ordinaryRolePolicyViolated) {
permissionProhibitedPageIds.push(nonLazyRouteItem.name);
}
else {
nonLazyRouteItem.invisible = false;
}
}
});
this.stopMenuScan$.next(null);
this.stopMenuScan$.complete();
this.routesService.remove(permissionProhibitedPageIds);
this.mapBindingComplete = true;
this.stopMenuScan$ = new ReplaySubject(1);
});
this.modulePermissionsService.getModulePermissionMap()
.pipe(takeUntil(this.destroy))
.subscribe(modulePermissionMap => {
this.mapBindingComplete = false;
this.modulePermissionMap$.next(modulePermissionMap);
});
}
deinit() {
this.destroy.next(null);
this.destroy.complete();
}
}
Usage - app.component.ts:
ngOnInit(): void {
this.oAuthService.events
.pipe(filter(event => event?.type === 'logout'))
.subscribe(() => {
this.modulePermissionHandler.deinit();
});
this.currentUser$.subscribe(currentUser => {
if (currentUser?.isAuthenticated) {
this.modulePermissionHandler.init();
}
});
}
And - yes - I had also to override PermissionGuard
: I have copy-pasted this from route.provider.ts to app-routing.module.ts:
and check this.modulePermissionMap$
in CanActivate
method.