比正常情况下更进一步地自定义ASP.NET成员身份提供程序

本文关键字:成员 NET 身份 程序 ASP 自定义 情况下 更进一步 | 更新日期: 2023-09-27 17:53:09

我正在尝试使用尽可能多的开箱即用的ASP.NET安全性来构建一个web应用程序。我使用默认模式很容易地启动并运行了它,但现在我正试图进行一个简单的修改,却感到各种困惑。基本上,我所要做的就是使用通用的userID(例如字符串GUID(而不是用户名作为用户帐户的主键。在谷歌上搜索会产生许多关于如何从MembershipProvider继承的线程,但它们都假设您覆盖了相同的方法签名,如:CreateUser(字符串用户名、字符串密码…(。我有点不知所措,因为我不知道引发了什么事件,导致调用::CreateUser((,也不知道要覆盖什么方法/类来更改它的调用方式。

是的,我知道在这种特殊的情况下,我可以"假装"用户名是userID,但我真的很想了解这是如何工作的,以防我将来想制作更多的MOD。

此外,我正在尝试自定义授权cookie中存储的信息,但我认为我已经掌握了这一点。下面显示了一些处于当前半生不熟状态的相关代码。谢谢

MyMembershipProvider.cs

namespace MyOrg.MyApp.Infrastructure
{
    public class MyAppMembershipProvider : MembershipProvider
    {
        int minPasswordLength = MyOrg.MyApp.Common.Config.minPasswordLength;
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            /* WANT TO SWITCH THIS OVER SO IT USES userID INSTEAD OF username */
            User user = null;
            using (DB db = new DB())
            {
                DateTime creationDate = DateTime.UtcNow;
                user = new User() {
                    username = username,
                    email = email,
                    pwd = MyOrg.Utilities.Misc.PasswordHash.CreateHash(password)
                };
                int recAdded = db.insertUser(user);
                if (recAdded > 0)
                {
                    status = MembershipCreateStatus.Success;
                }
                else
                {
                    status = MembershipCreateStatus.UserRejected;
                }
            }
            return getMembershipUserFromUser(user);
        }
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            /* WANT TO SWITCH THIS OVER SO IT USES userID INSTEAD OF username */
            User user = null;
            using (DB db = new DB())
            {
                user = db.getUser(username);
            }
            return getMembershipUserFromUser(user);
        }
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            /* WANT TO SWITCH THIS OVER SO IT USES userID INSTEAD OF username */
            User user = null;
            using (DB db = new DB())
                user = db.getUser(username);
            bool result = PasswordHash.ValidatePassword(oldPassword, user.pwd);
            if (result)
            {
                user.pwd = Utilities.Misc.PasswordHash.CreateHash(newPassword);
                user.lastPwdChange = DateTime.UtcNow;
                using (DB db = new DB())
                    db.updateUser(user);
            }
            return result;
        }
        public static bool ValidateUser(string username, string password, out string userID)
        {
            /* WANT TO SWITCH THIS OVER SO IT USES userID INSTEAD OF username */
            userID = null;
            using (DB db = new DB())
            {
                User user = db.getUserByUsername(username);
                if (user == null)
                    return false;
                bool result = MyOrg.Utilities.Misc.PasswordHash.ValidatePassword(password, user.pwd);
                if (result)
                {
                    user.failedPwdAttemptCount = 0;
                    user.failedPwdAnswerAttemptCount = 0;
                    user.lastLogin = DateTime.UtcNow;
                    userID = user.id;
                }
                else
                {
                    user.failedPwdAttemptCount++;
                    user.failedPwdAttemptWindowStart = DateTime.UtcNow;
                }
                db.updateUser(user);
                return result;
            }
        }
        private MembershipUser getMembershipUserFromUser(User user)
        {
            return new MembershipUser(
                "MyAppMembershipProvider",
                user.username,
                "dunno",
                user.email,
                user.pwdQuestion,
                user.comment,
                user.isApproved,
                user.isLockedOut,
                user.created,
                user.lastLogin,
                user.lastActivity,
                user.lastPwdChange,
                user.lastLockedOut);
        }
        public override int MinRequiredPasswordLength
        {
            get { return minPasswordLength; }
        }
        /* Other inherited methods not implemented*/

    }
}

AccountController.cs

namespace MyOrg.MyApp.Controllers
{
    public class AccountController : BaseController
    {
        public ActionResult LogOn()
        {
            return View();
        }
        [HttpPost]
        public ActionResult LogOn(FormCollection form)
        {
            string username = form["username"];
            string password = form["password"];
            bool rememberMe = form["rememberMe"] != null;
            string returnUrl = form["returnUrl"];
            string userID;
            if (MyAppMembershipProvider.ValidateUser(username, password, out userID))
            {
                CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
                serializeModel.userID = userID;
                serializeModel.username = username;
                System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
                string userData = serializer.Serialize(serializeModel);
                FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                  1,
                  userID,
                  DateTime.Now,
                  DateTime.Now.AddMinutes(15),
                  false,
                  userData);
                string encTicket = FormsAuthentication.Encrypt(authTicket);
                HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
                Response.Cookies.Add(faCookie);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ViewBag.validationMsg = "The user name or password provided is incorrect.";
            }
            // If we got this far, something failed, redisplay form
            ViewBag.username = username;
            return View();
        }
        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }
        public ActionResult Details()
        {
            RegisterModel model = new RegisterModel();
            User user;
            UserProfile profile;
            using (DB db = new DB())
            {
                user = db.getUser(User.userID);
                profile = db.getUserProfile(User.userID);
            }
            model.UserName = user.username;
            model.Email = user.email;
            model.Zip = profile.get(UserProfile.Properties.zip);
            return View(model);
        }
        public ActionResult Edit()
        {
            RegisterModel model = new RegisterModel();
            model = null;

            User user;
            UserProfile profile;
            using (DB db = new DB())
            {
                user = db.getUser(User.userID);
                profile = db.getUserProfile(User.userID);
            }
            model.UserName = user.username;
            model.Email = user.email;
            model.Zip = profile.get(UserProfile.Properties.zip);
            return View(model);
        }
        [HttpPost]
        public ActionResult Edit(RegisterModel model)
        {
            UserProfile profile = new UserProfile();
            profile.userID = model.UserName;
            profile.set(UserProfile.Properties.zip, model.Zip);
            using (DB db = new DB())
            {
                User user = db.getUser(model.UserName);
                user.email = model.Email;
                db.updateUser(user);
                db.updateUserProfile(profile);
            }
            return RedirectToAction("Index", "Home");
        }
        public ActionResult Register()
        {
            RegisterModel m = new RegisterModel();
            return View(m);
        }
        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            using (DB db = new DB())
            {
                // Check unique username
                if (db.getUser(model.UserName) != null)
                {
                    ViewBag.validationMsg = String.Format("The username '{0}' is already taken. Please choose another.", model.UserName);
                    return View();
                }
                Membership.CreateUser(model.UserName, model.Password, model.Email);
                UserProfile profile = new UserProfile();
                profile.userID = model.UserName;
                profile.set(UserProfile.Properties.zip, model.Zip);
                db.insertUserProfile(profile);
                string confirmationCode = Guid.NewGuid().ToString();
                db.insertConfirmationCode(model.UserName, confirmationCode);
                // Send Email w/ confirmation code
                Infrastructure.AccountConfirmationEmail email = new Infrastructure.AccountConfirmationEmail(
                    model.Email,
                    model.UserName,
                    confirmationCode
                );
                email.send();
            }
            return View("ConfirmationEmailSent");
        }
        public ActionResult Confirm(string username, string code)
        {
            ViewBag.username = username;
            ViewBag.code = code;
            return View();
        }
        [HttpPost]
        public ActionResult Confirm(string username, string code, string password)
        {
            string storedCode = null;
            using (DB db = new DB())
                storedCode = db.getConfirmationCode(username);
            if (storedCode == null)
            {
                // Username not found in confirmation_codes
                return View("ConfirmationCodeNotFound");
            }
            else
            {
                if (code == storedCode)
                {
                    if (Membership.ValidateUser(username, password))
                    {
                        using (DB db = new DB())
                        {
                            User user = db.getUser(username);
                            user.isConfirmed = true;
                            db.updateUser(user);
                            db.deleteConfirmationCode(username);
                            FormsAuthentication.SetAuthCookie(username, false); 
                            return RedirectToAction("Index", "Home");
                        }
                    }
                    else
                    {
                        ViewBag.username = username;
                        ViewBag.code = code;
                        ViewBag.validationMsg = "Incorrect Password";
                        return View();
                    }
                }
                else
                {
                    return View("ConfirmationCodeNotFound");
                }
            }
        }
        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }
        [Authorize]
        [HttpPost]
        public ActionResult ChangePassword(string OldPassword, string NewPassword)
        {
            bool changePasswordSucceeded;
            try
            {
                MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
                changePasswordSucceeded = currentUser.ChangePassword(OldPassword, NewPassword);
            }
            catch (Exception)
            {
                changePasswordSucceeded = false;
            }
            if (changePasswordSucceeded)
            {
                return RedirectToAction("ChangePasswordSuccess");
            }
            else
            {
                ViewBag.validationMsg = "The old password is incorrect.";
                ViewBag.newPassword = NewPassword;
            }
            // If we got this far, something failed, redisplay form
            return View();
        }
        [Authorize]
        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

    }
}

Global.asax.cs

namespace MyOrg.MyApp
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //filters.Add(new HandleErrorAttribute());
            filters.Add(new Infrastructure.HandleExceptionsAttribute()); // Implementing custom exception handling
        }
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }
        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie != null)
            {
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
                string userID = ticket.Name;
                CustomPrincipal principal = new CustomPrincipal(userID);
                HttpContext.Current.User = principal;
            }
        }
        protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie != null)
            {
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
                CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
                newUser.userID = serializeModel.userID;
                newUser.username = serializeModel.username;
                HttpContext.Current.User = newUser;
            }
        }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

Web.config

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="***" connectionString="***" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
    <machineKey
      validationKey="***"
      decryptionKey="***"
      validation="SHA1" />
    <membership defaultProvider="MyAppMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add
          name="MyAppMembershipProvider"
          type="MyOrg.MyApp.Infrastructure.MyAppMembershipProvider"
          connectionStringName="dummy"
          enablePasswordReset="true"
          requiresQuestionAndAnswer="true"
          writeExceptionsToEventLog="true" />
      </providers>
    </membership>
    <roleManager enabled="false">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages"/>
      </namespaces>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

比正常情况下更进一步地自定义ASP.NET成员身份提供程序

public override MembershipUser CreateUser(string username, ...)
{
   /* WANT TO SWITCH THIS OVER SO IT USES userID INSTEAD OF username */
}

很遗憾,您无法修改Membership Provider方法的参数。

以下是的基本概念

步骤1

当用户在登录控制中输入用户名和密码时,Membership Provide会调用ValidateUser。然后创建身份验证票证并将用户名保存在加密的cookie中。

步骤2

当用户请求子序列页面时,Membership Provider从cookie中检索用户名,并调用GetUser