Skip to content

Abstracted account validation#7944

Merged
MatteoPiovanelli merged 6 commits into
OrchardCMS:devfrom
LaserSrl:AccountValidationService
Jan 14, 2022
Merged

Abstracted account validation#7944
MatteoPiovanelli merged 6 commits into
OrchardCMS:devfrom
LaserSrl:AccountValidationService

Conversation

@MatteoPiovanelli

Copy link
Copy Markdown
Contributor

Added a service to abstract some account validation away from the AccountController, so it's easier to upgrade it and use the same validation elsewhere.

The idea is to make it easier to use the same validation across all modules when dealing with user registration. On top of that, eventually adding validation policies is easier this way.

The reasoning behind the methods from the interface is to cover the most common "parameters" of user registration (username, password, email). I did not add a ValidateRegistration method because different systems may have much different requirements there (e.g. we may not want password confirmation, or maybe we are not going to have an input for the username).

@sebastienros

Copy link
Copy Markdown
Member

The only issue I see is that the localization strings will need to be updated, and these are quite used. Maybe just keep the email validation in the controller? It's ugly, but it doesn't break existing users.

@MatteoPiovanelli

Copy link
Copy Markdown
Contributor Author

I can see the point you are making, but I'd still have validation in a single place, rather than copy-paste it in everyplace I need to use it. It's more maintainable in the long term, I think.

On the other hand, I can't think of a realistic scenario where I would need different email validation.

using Orchard.Localization;

namespace Orchard.Security {
public interface IAccountValidationService : IDependency {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why so many methods and not just one method with a UserVallidationContext ?
You could do validation that needs many of these properties.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had thought of that, but decided against it.
The reason was to provide building blocks for a method like that so that with a single implementation of this service it would be possible to build different validation "combinations".
For example, the ValidateRegistration method of AccountController uses these methods, then adds a check for the password confirmation.
Suppose in the same tenant I want to have a newsletter service, that would allowme to send newsletters to people that are not registered on the tenant. The "registration" for a newsletter may skip the password and username validations entirely, but may still check for unicity (I would add this in the method from the controller, like it's done in the AccountController).
If I had a single big method with an implementation doing all the validations, that would be injected in both of those controllers, and then I would require the passed context to have a lot of properties to control the validation steps to perform, and possibly their order.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree. If you need a newsletter module to create accounts then you should handle it by either using the same default logic that is used for new accounts, or create a custom one.

Also by separating all calls you can't ensure a rule where a password for a user can't be reused. Just an example.

/// </summary>
/// <param name="userName">The string we are evaluating as a UserName.</param>
/// <returns>true if the string is a valid UserName, false otherwise.</returns>
bool ValidateUserName(string userName);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have two different methods?
Also an out parameter is not necessary if it a referenced instance like a dictionary. Just pass an existing dictionary, or use an out array.

…ountController, so it's easier to upgrade it and use the same validation elsewhere.
@MatteoPiovanelli

MatteoPiovanelli commented Dec 17, 2021

Copy link
Copy Markdown
Contributor Author

I rebased this on the current dev branch.

I think I took care of most of the comments.
@sebastienros would you give this a look?

I still kept three separate methods to validate Password, UserName and Email, rather than a single method to validate the whole thing. My reasoning is as follows:

  • formal validation of the Email has me test that it's not empty.
  • If I want to just validate the password, I would not put a value in the Email property of the context.
  • If I had a single method then, that would fail, unless I added more information to the context to enable the service to figure out exactly the bits that should be validated.

Don't merge this yet as I update the code based on the comments and suggestions here and what we'll do for #8516

@MatteoPiovanelli

Copy link
Copy Markdown
Contributor Author

I think merging #8521 should take priority over this.

@MatteoPiovanelli
MatteoPiovanelli merged commit 1e1668f into OrchardCMS:dev Jan 14, 2022
@MatteoPiovanelli
MatteoPiovanelli deleted the AccountValidationService branch January 14, 2022 10:18
MatteoPiovanelli pushed a commit to LaserSrl/Orchard that referenced this pull request Jan 18, 2022
* Added a service to abstract some account validation away from the AccountController, so it's easier to upgrade it and use the same validation elsewhere.

* Added a validation context to carry information used for validation of account
information.

* Refactored password validation in the AccountController

* Updated tests

* fixed value read from context.ValidationSuccessful
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants