You can create some permissions
We have a list of module IDs (each module can be considered as a separate page in navigation menu) and we would prefer not to mix that with "permissions", since it's another conception. And we would like to use it in parallel with requiredPolicy
as shown in screenshot:
ModuleId
needs to be checked in Licence Provider and decide whether the given user has access to the given module ID (page): if not - the page is not displayed in the navigation menu neither user can access data for it.
Can you try the latest? 4.3.2
I've tried 4.3.2 and now Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
is not triggered at all for a logged user: is it correct behavior? When it needs to be triggered??
The angular permission check happens locally, the server will check all the permissions of the current user or user's role etc and return to angular. The menu just checks whether the permission is granted
Yes, I understand - but how to extend "permissions" functionality and use some custom things like our moduleId
in our licence provider?
@maliming thank you, i've tried this, but did not succeed:
Issue #1:
when user is logged in, for some reason context.Permissions
is empty here, so I am getting exception (while a user is not logged in - the context.Permissions
contains all proper data):
public override async Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
var moduleId = _abxRequestContext.AbxModuleId;
var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToArray(); // context.Permissions is empty!
Issue #2:
I need to get access to custom data for my navigation menu items: meanwhile we use custom field - moduleId
- to pass the accessed page information to server (moduleId is written to our custom IAbxRequestContext
object via our middleware and and eventually is logged to DB table and used in other places). This field was also supposed to be used to identify the page to access via licence permission. But of course PermissionValuesCheckContext
does not contain this data from Angular routing item. Neither IAbxRequestContext
object data is available yet. So how to pass data from navigation menu to CheckAsync
method and decide on what to display and what - not to display?
Issue #3:
is there some ABP cache mechanism to be consumed for caching licence data? Otherwise we would need to re-read this data from DB via appservice each time CheckAsync
is called.
p.s. since we seem to have a noticeable timeshift and not able to correspond in real-time - please provide me with as much detailed answer as possible so i could analyze this approach and find out what's wrong now...
We would like to have permission mechanism on top of existing permission architecture.
For instance, current tenant's company have bound licences, each of licence determines which UI pages ("modules") are accessible for current user. Thus, is the logged-in user has no access to the given page - it has to be hidden from UI navigation route - even before checking the given app / role permissions.
How to implement this mechanism?
I've tried to override existing ABP PermissionChecker
class, doing my licence check there in IsGrantedAsync
, but such approach does not look fully right: I am getting error 403 if there is no access, but instead I need to have the menu item completely hidden from my Angular app navigation route. I need backend mechanism which works for both backend and frontend part.
@albert
I checked it but I couldn't see any logic to disable these tabs. The marked tabs are bootstrap dropdown toggles. Maybe this is not working in your browser. Can you try it on a different browser and send me the results?
I have not noticed, but someone in the team redefined the CSS - as a result, a tab was clicked, but its dropdown content was not displayed. Thank you for the reply!
I need to use logical conditions (mainly "OR") for some AbpController
calls. I need to have it transparent, so the best way is to extend Authorize
attribute functionality.
I've read your documentation about Authorization - https://docs.abp.io/en/abp/latest/Authorization - but found nothing that would suit my needs.
You used to use AbpAuthorize
and similar attributes on different layers which allowed to supply an array of policies and AND / OR indicator (RequireAllPermissions
).
Seems like it is not used anymore (at least, I could not make it work).
Well, OK - if you are using AuthorizeAttribute
from Microsoft now - I found the article describing similar task and overrode a bunch of classes (but reused some of your code), please see the attach:
https://1drv.ms/u/s!AhWdpZddvifTtjEHoKMud74vu7No?e=LmsXGB
HttpApiHostModule
:
public override void ConfigureServices(ServiceConfigurationContext context)
{
...
context.Services.AddSingleton<IAuthorizationHandler, AbxPermissionHandler>();
context.Services.AddSingleton<IAuthorizationPolicyProvider, AbxPermissionAuthorizationPolicyProvider>();
}
Now in general it works, but I am not sure it's fully correct. Could you please have a look? Is there an easier way to do what I want?
One more question: some ABP UI controls are extended by us, i.e. we took ABP components and injected them in our components or just copied a source code (User, Organization Units, Tenants, etc.). For such controls we have own permissions. But the issue now is we have both ABP and own permissions and sometimes it is required to tick them all to make UI control work without erors. Is there an easier way, i.e. to tick only OUR permissions and make whole control work without 401 / 403 errors?
Also I am not very happy there is limitation for two permissions in *abpPermission directive in Angular UI: is there easy way to have more?
Call:
[AbxPermissionAuthorize(PermissionOperator.Or, CentralToolsPermissions.Licences.Default, CentralToolsPermissions.Modules.Default)]
public class LicenceController : AbpController
Or probably I need to use TypeFilterAttribute
instead?
Seems like I have managed to write it properly. Could you please regain my commercial tickets count, since I've resolved this one myself??
public override async Task ResetPasswordAsync(ResetPasswordDto input)
{
await IdentityOptions.SetAsync();
var currentUser = await UserManager.GetByIdAsync(input.UserId);
var tenants = await _abxUserRepository.FindTenantsByLoginAsync(currentUser.UserName);
foreach (var tenant in tenants)
{
using (CurrentTenant.Change(tenant.AbpId))
{
var abxUser = await _abxUserRepository.FindUserByLoginAsync(currentUser.UserName, tenant.Id);
var tenantUser = await UserManager.GetByIdAsync(abxUser.Id);
var tenantUserResetToken = await UserManager.GeneratePasswordResetTokenAsync(tenantUser);
(await UserManager.ResetPasswordAsync(tenantUser, tenantUserResetToken, input.Password)).CheckErrors();
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentitySecurityLogActionConsts.ChangePassword
});
}
}
}
I have the following error in my solution running on ABP 4.3.0 after submitting a new password in the forgotten password box: "VerifyUserTokenAsync() failed with purpose: ResetPassword for user."
I test everything on localhost in VS debug mode using a non-default tenant. As far as I remember, it used to work in the ABP 3.x.x. Any ideas, suggestions?
On other hand, ResetPassword
works OK in test generated 4.3.0 solution on default tenant. So I cannot figure out what could be wrong...
What I have noticed is that ResetToken
is a bit shorter in Test app...
Just in case if it matters: I have custom ProfileAppService
.
Please make a note I am trying this code now:
public override async Task ResetPasswordAsync(ResetPasswordDto input)
{
await IdentityOptions.SetAsync();
var user = await UserManager.GetByIdAsync(input.UserId);
(await UserManager.ResetPasswordAsync(user, input.ResetToken, input.Password)).CheckErrors();
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentitySecurityLogActionConsts.ChangePassword
});
}
But since I need to change the password for ALL TENANTS having such loginname I will need to use a custom implementation of AccountAppService
:
public override async Task ResetPasswordAsync(ResetPasswordDto input)
{
await IdentityOptions.SetAsync();
var currentUser = await UserManager.GetByIdAsync(input.UserId);
var tenants = await _abxUserRepository.FindTenantsByLoginAsync(currentUser.UserName);
foreach (var tenant in tenants)
{
using (CurrentTenant.Change(tenant.AbpId))
{
var tenantUser = await UserManager.GetByIdAsync(input.UserId);
// Generate reset token for tenantUser!
(await UserManager.ResetPasswordAsync(tenantUser, /*resetToken for tenantUser */, input.Password)).CheckErrors();
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentitySecurityLogActionConsts.ChangePassword
});
}
}
}