Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples, to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, please use the search on the homepage.
- ABP Framework version: v3.2.1
- UI type: Angular
- Tiered (MVC) or Identity Server Seperated (Angular): yes
- Exception message and stack trace:
- Steps to reproduce the issue:
Hi there, I have a special requirement in which i have to compare some custom validation against the default validation for password. Please have a following attached image 'RolesCreation', In which i customized the Role screen and added the custom validation as i want. They are working as expected, values are storing and retreiving without any issue. If you see below "Public" option there are custom validation settings which i added.
Now when i go to user creation and started entering password application showing validation message as per values we set to the default password settings. Please look attached image 'PasswordValidation '
At this screen i want to access the values of settings i created in Roles screen and i want to validation check the values from custom settings instead of default settings. Please help me on this. How and Where can implement this logic?
1 Answer(s)
-
0
Hello,
I will present two different ways to achieve what you are trying to do. However, keep in mind that the second option heavily relies on the internal implementation of the
UsersComponent
which could change in the future and we may introduce some breaking changes for that component. If you choose to follow the second option, it is your responsibility to ensure that your code is working. If there are some breaking changes, again it is your responsibility to edit your code accordingly.First Option: Override
UsersComponent
You could implement your own
users
page so that you can define any logic you'd like. Please refer to the docs for more detail about replacing components.The key for
UsersComponent
iseIdentityComponents.Users
Second Option: Override Password field in the form
You can override
password
field forNew user
modal.Please refer to the docs
Firstly, let's create a file and call it
identity-create-form-prop-contributors.ts
and add the following code block in it.export function customAsyncPasswordValidator(data: PropData<IdentityUserDto>) { // validator will come here } const passwordField = new FormProp<IdentityUserDto>({ type: ePropType.Password, name: 'password', displayName: 'AbpIdentity::Password', id: 'password', autocomplete: 'new-password', validators: _ => [Validators.required], asyncValidators: customAsyncPasswordValidator, }); export function userCreateFormContributor(formProps: FormPropList<IdentityUserDto>) { const index = formProps.indexOf('password', (action, name) => action.name === name); formProps.dropByIndex(index); formProps.addByIndex(passwordField, index); } export const identityCreateFormContributors: IdentityCreateFormPropContributors = { [eIdentityComponents.Users]: [userCreateFormContributor], };
Up to this point, we haven't done anything hacky yet. You can use this part confidently. It is the trivial way of overriding a field within an extensible form. However, the implementation of
customAsyncPasswordValidator
will be error-prone and depend on the internals ofUsersComponent
. It is up to you to decide whether to use the following implementation. It contains some comment aboutexport function customAsyncPasswordValidator(data: PropData<IdentityUserDto>) { const roleService = data.getInjected(IdentityRoleService); const user = data.getInjected(UsersComponent); /** * Retrieve the existing roles and filter them with name `Super Admin` */ const superAdminRoleDetails = roleService.getAllList().pipe( map(roles => roles.items.filter(role => role.name === 'Super Admin')), shareReplay(), // this exists so that we will only retrieve this list once. ); /** * If `Super Admin` is not selected, we should keep the default validators. * This function calls every validator with `control` to keep the default behavior. */ const defaultValidator = (control: FormControl) => of( getPasswordValidators({ get: data.getInjected }).reduce( (retVal, currValidator) => ({ ...retVal, ...currValidator(control) }), {}, ), ); const superAdminPasswordValidator = (control: FormControl) => superAdminRoleDetails.pipe( map(details => { if (details?.length) { const rules = details[0]; // You can write your custom rule here with rules.extraProperties return control.value !== '123456' ? { wrongPassword: true, } : null; } return null; }), ); const validator = control => { /** * Find if a role group exists with name `Super Admin` */ const superAdminGroup = user.roleGroups.find(roleGr => roleGr.contains('Super Admin')); if (superAdminGroup) { const isAdminSelected = superAdminGroup.controls['Super Admin'].value; return isAdminSelected ? superAdminPasswordValidator(control) : defaultValidator(control); } return defaultValidator(control); }; return [validator]; }
Finally, we need to add some imports to
app.module
andapp-routing.module
Import following into
app.module
@NgModule({ // ... imports: [ // ... NgxValidateCoreModule.forRoot({ blueprints: { wrongPassword: 'Please choose 123456', }, }) ] export class AppModule {}
And, update
app-routing.module
{ path: 'identity', loadChildren: () => import('@volo/abp.ng.identity').then(m => m.IdentityModule.forLazy({ // this line should be added createFormPropContributors: identityCreateFormContributors, }), ), },