使用 ASP.NET Membership 實作註冊功能時,Membership.CreateUser 返回 MembershipCreateStatus.InvalidPassword 或 InvalidEmail,導致 ModelState.IsValid 通過但建立失敗。根因多在 web.config Membership 設定與模型驗證屬性不一致。
[HttpPost]
public ActionResult Register(RegisterModel model) {
if (ModelState.IsValid) {
MembershipCreateStatus status;
Membership.CreateUser(model.UserName, model.Password, model.Email,
passwordQuestion: null, passwordAnswer: null,
isApproved: true, providerUserKey: null, out status);
if (status == MembershipCreateStatus.Success) {
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("LogOn", "Account");
}
ModelState.AddModelError("", ErrorCodeToString(status));
}
return View(model);
}
| 設定項 | web.config Membership | RegisterModel Attribute | 衝突後果 |
|---|---|---|---|
| 密碼長度 | minRequiredPasswordLength="7" | [StringLength(100, MinimumLength=6)] | 前端驗證通過 6 字,Membership 拒絕 → InvalidPassword |
| 非字母數字字符數 | minRequiredNonalphanumericCharacters="1" | 無對應驗證 | 用戶輸入純字母數字 → InvalidPassword |
| 密碼強度正則 | passwordStrengthRegularExpression="" | [RegularExpression(...)] | 雙重驗證邏輯不一致 |
| 郵件唯一 | requiresUniqueEmail="true" | [Remote("CheckEmail", "Account")] | 並發註冊同郵件 → DuplicateEmail |
| 用戶名格式 | 無內建限制 | [RegularExpression(@"^\w+$")] | Membership 允許郵件作用戶名,模型拒絕 |
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="ApplicationServices"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
public class RegisterModel {
[Required]
[Display(Name = "用戶名")]
[StringLength(50, MinimumLength = 3)]
[RegularExpression(@"^[\w\u4e00-\u9fa5]+$", ErrorMessage = "僅限字母、數字、下劃線、中文")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "密碼")]
[StringLength(100, MinimumLength = 6)] // 對應 minRequiredPasswordLength=6
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "確認密碼")]
[Compare("Password", ErrorMessage = "兩次輸入不一致")]
public string ConfirmPassword { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "電子郵件")]
[Remote("CheckEmailExists", "Account", ErrorMessage = "郵件已被註冊")]
public string Email { get; set; }
}
private string ErrorCodeToString(MembershipCreateStatus status) {
return status switch {
MembershipCreateStatus.DuplicateUserName => "用戶名已存在",
MembershipCreateStatus.DuplicateEmail => "郵件已被註冊",
MembershipCreateStatus.InvalidPassword => "密碼不符合要求 (長度、特殊字符)",
MembershipCreateStatus.InvalidEmail => "郵件格式無效",
MembershipCreateStatus.InvalidUserName => "用戶名包含非法字符",
MembershipCreateStatus.ProviderError => "提供者錯誤,請稍後再試",
_ => "未知錯誤"
};
}
web.config Membership 設定與 Model 驗證屬性完全一致 (長度、特殊字符、唯一性)。CreateUser 失敗時保留 ModelState,將 Membership 錯誤碼轉為友善訊息加入 ModelState.AddModelError。Remote 屬性 + 伺服端 Membership.GetUserNameByEmail 檢查,但仍需捕獲 DuplicateEmail 兜底 (並發)。// Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// 密碼策略配置
services.Configure<IdentityOptions>(options => {
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.User.RequireUniqueEmail = true;
});