Skip to content

Commit e76dfb8

Browse files
committed
Add custom validation attributes to login model.
1 parent 7c25cdc commit e76dfb8

13 files changed

+288
-1
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace Asp.NetCore.Services.Attributes
4+
{
5+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
6+
public class AtLeastOneNumberAttribute : ValidationAttribute
7+
{
8+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
9+
{
10+
var str = value as string;
11+
if (!string.IsNullOrEmpty(str))
12+
{
13+
// must contains at least one number
14+
if (!str.Any(char.IsDigit))
15+
{
16+
return new ValidationResult($"Must contains at least one number please.");
17+
}
18+
}
19+
return ValidationResult.Success;
20+
}
21+
}
22+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Asp.NetCore.Shared;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class AtLeastOneSpecialCharacterAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must contains at least one special character
15+
if (str.Any(x => Utilities.Characters.SpecialCharacter.Contains(x.ToString())) == false)
16+
{
17+
return new ValidationResult($"Must contains at least one special character i.e: ~`!@#$%^&*()_-+={{[}}]|\\:;\"'<,>?/. please.");
18+
}
19+
}
20+
return ValidationResult.Success;
21+
}
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class AtLeastOneUppercaseLetterOneLowercaseLetterAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must contains at least one uppercase letter and one lowercase letter
15+
Match atLeastOneUppercaseLetterOneLowercaseLetter = new Regex(@"^(?=.*[a-z])(?=.*[A-Z]).+$").Match(str);
16+
if (!atLeastOneUppercaseLetterOneLowercaseLetter.Success)
17+
{
18+
return new ValidationResult($"Must contains at least one uppercase letter and at least one lowercase letter please.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace Asp.NetCore.Services.Attributes
4+
{
5+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
6+
public class CustomRangeAttribute : ValidationAttribute
7+
{
8+
private readonly int _minLength;
9+
private readonly int _maxLength;
10+
11+
public CustomRangeAttribute(int minLength, int maxLength)
12+
{
13+
_minLength = minLength;
14+
_maxLength = maxLength;
15+
}
16+
17+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
18+
{
19+
var str = value as string;
20+
if (!string.IsNullOrEmpty(str) && str.Length < _minLength)
21+
{
22+
return new ValidationResult($"Requires a minimum length of {_minLength} characters.");
23+
}
24+
if (!string.IsNullOrEmpty(str) && str.Length > _maxLength)
25+
{
26+
return new ValidationResult($"Requires a maximum length of {_maxLength} characters.");
27+
}
28+
return ValidationResult.Success;
29+
}
30+
}
31+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class EnglishCharsAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must start with letter
15+
Match startWithLetter = new Regex(@"^[a-zA-Z0-9]+$").Match(str);
16+
if (!startWithLetter.Success)
17+
{
18+
return new ValidationResult($"Only accept English characters, numbers.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class EnglishCharsSpacesAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must start with letter
15+
Match startWithLetter = new Regex(@"^[a-zA-Z0-9 ]+$").Match(str);
16+
if (!startWithLetter.Success)
17+
{
18+
return new ValidationResult($"Only accept English characters, numbers, spacebars.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class EnglishCharsUnderscoresAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must start with letter
15+
Match startWithLetter = new Regex(@"^[a-zA-Z0-9_]+$").Match(str);
16+
if (!startWithLetter.Success)
17+
{
18+
return new ValidationResult($"Only accept English characters, numbers, underscores.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace Asp.NetCore.Services.Attributes
4+
{
5+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
6+
public class NoWhiteSpacesAtBeginningAndEndAttribute : ValidationAttribute
7+
{
8+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
9+
{
10+
var str = value as string;
11+
if (!string.IsNullOrEmpty(str) && (str.StartsWith(" ") || str.EndsWith(" ")))
12+
{
13+
return new ValidationResult($"Whitespace characters are not allowed at begin and end of this field.");
14+
}
15+
return ValidationResult.Success;
16+
}
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace Asp.NetCore.Services.Attributes
4+
{
5+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
6+
public class NoWhiteSpacesAttribute : ValidationAttribute
7+
{
8+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
9+
{
10+
var str = value as string;
11+
if (!string.IsNullOrEmpty(str) && str.Contains(" "))
12+
{
13+
return new ValidationResult($"Whitespace characters are not allowed at this field.");
14+
}
15+
return ValidationResult.Success;
16+
}
17+
}
18+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class StartWithLetterAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
// must start with letter
15+
Match startWithLetter = new Regex(@"^[a-zA-Z].+$").Match(str);
16+
if (!startWithLetter.Success)
17+
{
18+
return new ValidationResult($"Must start with a letter please.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Asp.NetCore.Services.Attributes
5+
{
6+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
7+
public class VietnameseCharsSpacesAttribute : ValidationAttribute
8+
{
9+
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
10+
{
11+
var str = value as string;
12+
if (!string.IsNullOrEmpty(str))
13+
{
14+
string pattern = @"^[0123456789qwertyuiopQWERTYUIOPèéẻẽẹÈÉẺẼẸềếểễệỀẾỂỄỆỳýỷỹỵỲÝỶỸỴùúủũụÙÚỦŨỤìíỉĩịÌÍỈĨỊòóỏõọÒÓỎÕỌồốổỗộỒỐỔỖỘaAàáảãạÀÁẢÃẠằắẳẵặẰẮẮẴẶầấẩẫậẦẤẨẪẬsSdDđĐfFgGhHjJkKlLzZxXcCvVbBnNmM\s]+$";
15+
Match startWithLetter = new Regex(pattern).Match(str);
16+
if (!startWithLetter.Success)
17+
{
18+
return new ValidationResult($"Please enter only Vietnamese characters, numbers and spaces.");
19+
}
20+
}
21+
return ValidationResult.Success;
22+
}
23+
}
24+
}

Asp.NetCore.Services/Models/Identity/LoginViewModel.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1-
namespace Asp.NetCore.Services.Models.Identity
1+
using Asp.NetCore.Services.Attributes;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace Asp.NetCore.Services.Models.Identity
25
{
36
public class LoginViewModel
47
{
8+
[Required(ErrorMessage = "Please enter the username")]
9+
[CustomRange(4, 50)]
10+
[NoWhiteSpacesAtBeginningAndEnd]
11+
[StartWithLetter]
12+
[EnglishCharsUnderscores]
513
public string? Username { get; set; }
614

15+
[Required(ErrorMessage = "Please enter the password")]
16+
[CustomRange(6, 30)]
17+
[NoWhiteSpacesAtBeginningAndEnd]
18+
[StartWithLetter]
19+
[AtLeastOneNumber]
20+
[AtLeastOneSpecialCharacter]
21+
[AtLeastOneUppercaseLetterOneLowercaseLetter]
722
public string? Password { get; set; }
823

924
public bool RememberMe { get; set; } = false;

Asp.NetCore.Shared/Utilities.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,21 @@ public class FolderPath
3232
{
3333

3434
}
35+
36+
public class Characters
37+
{
38+
/// <summary>
39+
/// Non-alphanumeric characters
40+
/// </summary>
41+
public static readonly List<string> SpecialCharacter = new List<string>()
42+
{
43+
"~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", "{", "[", "}", "]", "|", "\\", ":", ";", "\"", "'", "<", ">", ",", ".", "?", "/"
44+
};
45+
46+
public static readonly List<string> EscapeCharacters = new List<string>()
47+
{
48+
"\\", "\n", "\r", "\t", "\b"
49+
};
50+
}
3551
}
3652
}

0 commit comments

Comments
 (0)