You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
10 KiB
C#

10 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
namespace DSWebMobile.Models
{
#region 模型
[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "新密码和确认密码不匹配。")]
public class ChangePasswordModel
{
[Required]
[DataType(DataType.Password)]
[DisplayName("当前密码")]
public string OldPassword { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[DisplayName("新密码")]
public string NewPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("确认新密码")]
public string ConfirmPassword { get; set; }
}
public class LogOnModel
{
[Required]
[DisplayName("用户名")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("密码")]
public string Password { get; set; }
[DisplayName("记住我?")]
public bool RememberMe { get; set; }
}
[PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "密码和确认密码不匹配。")]
public class RegisterModel
{
[Required]
[DisplayName("用户名")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("电子邮件地址")]
public string Email { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[DisplayName("密码")]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("确认密码")]
public string ConfirmPassword { get; set; }
}
#endregion
#region Services
// FormsAuthentication 类型是密封的且包含静态成员,因此很难对
// 调用其成员的代码进行单元测试。下面的接口和 Helper 类演示
// 如何围绕这种类型创建一个抽象包装,以便可以对 AccountController
// 代码进行单元测试。
public interface IMembershipService
{
int MinPasswordLength { get; }
bool ValidateUser(string userName, string password);
MembershipCreateStatus CreateUser(string userName, string password, string email);
bool ChangePassword(string userName, string oldPassword, string newPassword);
}
public class AccountMembershipService : IMembershipService
{
private readonly MembershipProvider _provider;
public AccountMembershipService()
: this(null)
{
}
public AccountMembershipService(MembershipProvider provider)
{
_provider = provider ?? Membership.Provider;
}
public int MinPasswordLength
{
get
{
return _provider.MinRequiredPasswordLength;
}
}
public bool ValidateUser(string userName, string password)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不能为 null 或为空。", "userName");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("值不能为 null 或为空。", "password");
return _provider.ValidateUser(userName, password);
}
public MembershipCreateStatus CreateUser(string userName, string password, string email)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不能为 null 或为空。", "userName");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("值不能为 null 或为空。", "password");
if (String.IsNullOrEmpty(email)) throw new ArgumentException("值不能为 null 或为空。", "email");
MembershipCreateStatus status;
_provider.CreateUser(userName, password, email, null, null, true, null, out status);
return status;
}
public bool ChangePassword(string userName, string oldPassword, string newPassword)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不能为 null 或为空。", "userName");
if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("值不能为 null 或为空。", "oldPassword");
if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("值不能为 null 或为空。", "newPassword");
// 在某些出错情况下,基础 ChangePassword() 将引发异常,
// 而不是返回 false。
try
{
MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
return currentUser.ChangePassword(oldPassword, newPassword);
}
catch (ArgumentException)
{
return false;
}
catch (MembershipPasswordException)
{
return false;
}
}
}
public interface IFormsAuthenticationService
{
void SignIn(string userName, bool createPersistentCookie);
void SignOut();
}
public class FormsAuthenticationService : IFormsAuthenticationService
{
public void SignIn(string userName, bool createPersistentCookie)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不能为 null 或为空。", "userName");
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}
public void SignOut()
{
FormsAuthentication.SignOut();
}
}
#endregion
#region Validation
public static class AccountValidation
{
public static string ErrorCodeToString(MembershipCreateStatus createStatus)
{
// 请参见 http://go.microsoft.com/fwlink/?LinkID=177550 以查看
// 状态代码的完整列表。
switch (createStatus)
{
case MembershipCreateStatus.DuplicateUserName:
return "用户名已存在。请另输入一个用户名。";
case MembershipCreateStatus.DuplicateEmail:
return "已存在与该电子邮件地址对应的用户名。请另输入一个电子邮件地址。";
case MembershipCreateStatus.InvalidPassword:
return "提供的密码无效。请输入有效的密码值。";
case MembershipCreateStatus.InvalidEmail:
return "提供的电子邮件地址无效。请检查该值并重试。";
case MembershipCreateStatus.InvalidAnswer:
return "提供的密码取回答案无效。请检查该值并重试。";
case MembershipCreateStatus.InvalidQuestion:
return "提供的密码取回问题无效。请检查该值并重试。";
case MembershipCreateStatus.InvalidUserName:
return "提供的用户名无效。请检查该值并重试。";
case MembershipCreateStatus.ProviderError:
return "身份验证提供程序返回了错误。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。";
case MembershipCreateStatus.UserRejected:
return "已取消用户创建请求。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。";
default:
return "发生未知错误。请验证您的输入并重试。如果问题仍然存在,请与系统管理员联系。";
}
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' 和 '{1}' 不匹配。";
private readonly object _typeId = new object();
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmProperty = confirmProperty;
}
public string ConfirmProperty { get; private set; }
public string OriginalProperty { get; private set; }
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, ConfirmProperty);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
return Object.Equals(originalValue, confirmValue);
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ValidatePasswordLengthAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' 必须至少包含 {1} 个字符。";
private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;
public ValidatePasswordLengthAttribute()
: base(_defaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
name, _minCharacters);
}
public override bool IsValid(object value)
{
string valueAsString = value as string;
return (valueAsString != null && valueAsString.Length >= _minCharacters);
}
}
#endregion
}