是否可以将 .ASPXAUTH 用于我自己的日志系统?

发布于 2024-08-19 03:07:39 字数 262 浏览 5 评论 0原文

对于 Web 应用程序,我从使用 ASP.NET 会员资格切换到使用我自己的登录系统,该系统只是执行类似以下操作来将用户标记为已登录:

Session["UserId"] = User.Id

Is it possible to store the user id in the ASPXAUTH cookie, 捎带其加密,而不是使用标准会话?

目标是使登录状态持续的时间比会话更长,并且在浏览器和服务器重新启动后仍然存在。

For a web application I switched from using ASP.NET Membership to using my own log in system which just does something like this to mark a user as logged in:

Session["UserId"] = User.Id

Is it possible to store the user id in the ASPXAUTH cookie, piggybacking on its encryption, instead of using the standard session?

The goal is for the logged in state to last longer than a session and survive both browser and server restarts.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绮筵 2024-08-26 03:07:39

更新:提供的原始答案是使用 MembershipProvider 的项目,并且在答案本身中进行了解释。我,提问者,没有使用它,所以我的问题的答案略有不同,但从这个答案中提取。我将我的答案放在底部,供任何关心的人使用,并逐字保留原始内容,因为它包含很多价值。


是的,您可以将 FormsAuthentication 用于您自己的策略。虽然 asp.net 数据库结构不适合您,但您可以提供 MembershipProvider 的简单实现以允许使用 Membership 基础结构。这两个功能并没有结合在一起,因此您可以决定哪个功能适合您。

请记住您的问题和一些评论,这里是一个可运行的示例,说明在不与默认实现和数据库模式结合的情况下利用提供程序模型是多么简单。

将表单身份验证用于您自己的目的很简单。您只需要提供身份验证并设置您自己的票证(cookie)。

使用自定义会员资格几乎同样简单。您可以根据需要实现尽可能少或尽可能多的提供程序,以支持您想要使用的 ASP.NET 基础结构功能。

例如,在下面的示例中,我展示了在登录过程中,您可以简单地处理登录控件上的事件来验证凭据并设置票证。完毕。

但我还将展示如何利用提供程序模型和实现自定义成员资格提供程序可以产生更强大、更简洁的代码。当我们在自定义成员资格提供程序中时,我实现了支持使用成员资格子系统所需的最低限度,以提供对用户元数据的轻松访问,而无需编写自己的基础结构。

只需将这些文件放入一个空项目中即可。

web.config


<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true"/>
    <authorization>
      <deny users="?"/>
    </authorization>
    <authentication mode="Forms"/>
    <!-- 
    optional but recommended. reusing the membership infrastructure via custom provider divorces 
    you from the aspnetdb but retains all of the baked in infrastructure which you do not have to 
    develop or maintain
    -->
    <membership defaultProvider="mine">
      <providers>
        <add name="mine" type="CustomAuthRepurposingFormsAuth.MyMembershipProvider"/>
      </providers>
    </membership>
  </system.web>
</configuration>

Site1.Master


<%@ Master Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:LoginName ID="LoginName1" runat="server" />
        <asp:LoginStatus ID="LoginStatus1" runat="server" />
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

Login.aspx


<%@ Page Title="" Language="C#" MasterPageFile="Site1.Master" %>
<%@ Import Namespace="CustomAuthRepurposingFormsAuth" %>
<script runat="server">

    /*
     * If you don't want to use a custom membership provider to authenticate
     * simply place your logic in the login control's handler and remove the 
     * membership element from config. It would have to take a very very 
     * compelling edge case to motivate me to not use a custom membership provider.
     * 
     */

    //protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    //{
    //    // perform mindbendingly complex authentication logic
    //    e.Authenticated = Login1.UserName == Login1.Password;
    //}


    /*
     * set your cookie and you are golden
     */
    void Authenticated(object sender, EventArgs e)
    {
        // this is an arbitrary data slot you can use for ???
        // keep cookie size in mind when using it.
        string userData = "arbitraryData";
        Response.Cookies.Add(TicketHelper.CreateAuthCookie(Login1.UserName, userData, Login1.RememberMeSet /*persistent cookie*/));
    }

</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <asp:Login ID="Login1" runat="server" OnLoggedIn="Authenticated" >
    </asp:Login>
    username==password==authenticated. <br />e.g.: uid: me, pwd:me
</asp:Content>

Default.aspx


<%@ Page Title="" Language="C#" MasterPageFile="Site1.Master" %>

<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="CustomAuthRepurposingFormsAuth" %>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        /*
         * you get this for free from asp.net
         */

        HttpContext page = HttpContext.Current;

        IIdentity identity = page.User.Identity;
        string username = identity.Name;
        bool authenticate = identity.IsAuthenticated;
        // or use the Request.IsAuthenticated convenience accessor

        /* 
         * you get this really cheap from forms auth
         * 
         * cost: validating credentials and setting your own ticket
         */

        // this page is protected by formsauth so the identity will actually 
        // be a FormsIdentity and you can get at the user data.
        // UserData is an appropriate place to store _small_ amounts of data
        var fIdent = (FormsIdentity)identity;
        string userData = fIdent.Ticket.UserData;


        // so, using only forms auth this is what you have to work with
        LblAuthenticated.Text = page.User.Identity.IsAuthenticated.ToString();
        LblUserId.Text = page.User.Identity.Name;
        LblUserData.Text = userData;

        /* 
         * this is an example of using a custom membership provider and subclassing the 
         * MembershipUser class to take advantage of the established mature infrastructure
         * 
         * this is entirely optional, you can delete the Membership section in web.config 
         * and delete MyMembershipProvider and MyMembershipUser and just use the authentication.
         * 
         */

        // get the custom field
        string myCustomField = ((MyMembershipUser)Membership.GetUser()).MyCustomField;
        LblMembership.Text = myCustomField;
    }        
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <br />
    Authenticated:<asp:Label ID="LblAuthenticated" runat="server" Text=""></asp:Label><br />
    UserId:<asp:Label ID="LblUserId" runat="server" Text=""></asp:Label><br />
    UserData:<asp:Label ID="LblUserData" runat="server" Text=""></asp:Label><br />
    <br />
    Membership User Custom Field:<asp:Label ID="LblMembership" runat="server" Text=""></asp:Label><br />
</asp:Content>

CustomAuthClasses.cs


using System;
using System.Web;
using System.Web.Security;

namespace CustomAuthRepurposingFormsAuth
{
    public static class TicketHelper
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="userData">be mindful of the cookie size or you will be chasing ghosts</param>
        /// <param name="persistent"></param>
        /// <returns></returns>
        public static HttpCookie CreateAuthCookie(string userName, string userData, bool persistent)
        {
            DateTime issued = DateTime.Now;
            // formsAuth does not expose timeout!? have to hack around the
            // spoiled parts and keep moving..
            HttpCookie fooCookie = FormsAuthentication.GetAuthCookie("foo", true);
            int formsTimeout = Convert.ToInt32((fooCookie.Expires - DateTime.Now).TotalMinutes);

            DateTime expiration = DateTime.Now.AddMinutes(formsTimeout);
            string cookiePath = FormsAuthentication.FormsCookiePath;

            var ticket = new FormsAuthenticationTicket(0, userName, issued, expiration, true, userData, cookiePath);
            return CreateAuthCookie(ticket, expiration, persistent);
        }

        public static HttpCookie CreateAuthCookie(FormsAuthenticationTicket ticket, DateTime expiration, bool persistent)
        {
            string creamyFilling = FormsAuthentication.Encrypt(ticket);
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, creamyFilling)
                             {
                                 Domain = FormsAuthentication.CookieDomain,
                                 Path = FormsAuthentication.FormsCookiePath
                             };
            if (persistent)
            {
                cookie.Expires = expiration;
            }

            return cookie;
        }
    }

    /// <summary>
    /// This is an example of inheriting MembershipUser to
    /// expose arbitrary data that may be associated with your
    /// user implementation.
    /// 
    /// You may repurpose existing fields on the base and add your own.
    /// Just perform a cast on the MembershipUser returned from your
    /// MembershipProvider implementation
    /// </summary>
    public class MyMembershipUser : MembershipUser
    {
        public MyMembershipUser(string providerName, string name, object providerUserKey, string email,
                                string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
                                DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate,
                                DateTime lastPasswordChangedDate, DateTime lastLockoutDate)
            : base(
                providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut,
                creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate)
        {
        }

        protected MyMembershipUser()
        {
        }

        // e.g. no desire to use Profile, can just add data
        // say, from a flat record containing all user data
        public string MyCustomField { get; set; }
    }

    /// <summary>
    /// At the most basic level, implementing a MembershipProvider allows you to
    /// reuse established framework code. In this case, we just provide services
    /// for the Login control and user identification via Membership subsystem.
    /// </summary>
    public class MyMembershipProvider : MembershipProvider
    {
        #region Minimum implementation in order to use established authentication and identification infrastructure

        /// <summary>
        /// You can just do this in the login logic if you do not want
        /// leverage framework for membership user access
        /// </summary>
        public override bool ValidateUser(string username, string password)
        {
            return username == password;
        }


        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            /*
             * Simulate going to the DB to get the data
             */

            // membership user non nullable fields, repurpose or use
            // implied null value e.g DateTime.MinValue;

            var createdDate = new DateTime(2009, 10, 25);
            var lastLogin = new DateTime(2009, 10, 25);
            var lastActivity = new DateTime(2009, 10, 25);
            var lastPasswordChange = new DateTime(2009, 10, 25);
            var lastLockoutDate = new DateTime(2009, 10, 25);

            object providerUserKey = 3948; // e.g. user primary key. 


            /*
             * build your custom user and send it back to asp.net
             */

            // need to use the full constructor to set the username and key
            var user = new MyMembershipUser(Name, username, providerUserKey, null, null, null, true, false, createdDate,
                                            lastLogin,
                                            lastActivity, lastPasswordChange, lastLockoutDate)
                           {
                               MyCustomField = "Hey"
                           };

            return user;
        }

        #endregion

        #region Optional implementations depending on the framework features you would like to leverage.

        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); }
        }

        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }

        public override string ApplicationName
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }


        public override MembershipUser CreateUser(string username, string password, string email,
                                                  string passwordQuestion, string passwordAnswer, bool isApproved,
                                                  object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password,
                                                             string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }


        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
                                                                 out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
                                                                  out int totalRecords)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

实际使用的解决方案(在使用 OpenID 的 ASP.NET MVC 项目中):

我有一个 AccountController,我用它来登录和注销用户,这些方法就在那里。

#region Methods to log in a user.
/// <summary>
/// Create the auth cookie in the same way it is created my ASP.NET Membership system, hopefully lasting for more than 20 minutes.
/// 
/// For more information check out http://stackoverflow.com/questions/2122831/is-it-possible-to-use-aspxauth-for-my-own-logging-system
/// </summary>
/// <param name="userId">Id of the user that is logged in</param>
/// <returns>Cookie created to mark the user as authenticated.</returns>
private static HttpCookie CreateAuthCookie(int userId) {
  DateTime issued = DateTime.Now;
  // formsAuth does not expose timeout!? have to hack around the spoiled parts and keep moving..
  HttpCookie fooCookie = FormsAuthentication.GetAuthCookie("foo", true);
  int formsTimeout = Convert.ToInt32((fooCookie.Expires - DateTime.Now).TotalMinutes);

  DateTime expiration = DateTime.Now.AddMinutes(formsTimeout);

  var ticket = new FormsAuthenticationTicket(0, userId.ToString(), issued, expiration, true, "", FormsAuthentication.FormsCookiePath);
  return CreateAuthCookie(ticket, expiration, true);
}

/// <summary>
/// Create an auth cookie with the ticket data.
/// </summary>
/// <param name="ticket">Ticket containing the data to mark a user as authenticated.</param>
/// <param name="expiration">Expriation date for the cookie.</param>
/// <param name="persistent">Whether it's persistent or not.</param>
/// <returns>Cookie created to mark the user as authenticated.</returns>
private static HttpCookie CreateAuthCookie(FormsAuthenticationTicket ticket, DateTime expiration, bool persistent) {
  string encryptedAuthData = FormsAuthentication.Encrypt(ticket);
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedAuthData) {
    Domain = FormsAuthentication.CookieDomain,
    Path = FormsAuthentication.FormsCookiePath
  };
  if (persistent) {
    cookie.Expires = expiration;
  }

  return cookie;
}

/// <summary>
/// Expire the authentication cookie effectively loging out a user.
/// </summary>
private void ExpireAuthCookie() {
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
  cookie.Expires = DateTime.Now.AddDays(-1);
  Response.Cookies.Add(cookie);
}
#endregion

Update: The original answer provided was with a project using MembershipProvider and it's explained in the answer itself. I, the asker, am not using it, so the answer to my problem was slightly different but extracted from this answer. I'm putting my answer at the bottom for anyone that cares and leaving the original verbatim, as it contains a lot of value.


Yes, you can use FormsAuthentication for your own strategy. And while the asp.net db structure does not suit you, you may provide a simple implementation of MembershipProvider to allow use of the Membership infrastructure. These two functionalities are not married so you may decide what fits for you.

Keeping in mind your question and some of the comments, here is a runnable example of how simple it is to leverage the provider model without being married to the default implementations and db schemas.

Using forms auth for your own purposes is simple. You just need to provide authentication and set your own ticket (cookie).

Using custom membership is almost as simple. You can implement as little or as much of the provider as you need to support the asp.net infrastructure features that you would like to employ.

e.g. in the sample below, I show that in the login process you may simply handle an event on the login control to validate credentials and the set the ticket. Done.

But I will also show how leveraging the provider model and implementing a custom membership provider can result in stronger, cleaner code. While we are in the custom membership provider I implement the minimum necessary to support using the Membership subsystem to provide easy access to a user's meta data without the need to write your own infrastructure.

Just drop these files into an empty project.

web.config


<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true"/>
    <authorization>
      <deny users="?"/>
    </authorization>
    <authentication mode="Forms"/>
    <!-- 
    optional but recommended. reusing the membership infrastructure via custom provider divorces 
    you from the aspnetdb but retains all of the baked in infrastructure which you do not have to 
    develop or maintain
    -->
    <membership defaultProvider="mine">
      <providers>
        <add name="mine" type="CustomAuthRepurposingFormsAuth.MyMembershipProvider"/>
      </providers>
    </membership>
  </system.web>
</configuration>

Site1.Master


<%@ Master Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:LoginName ID="LoginName1" runat="server" />
        <asp:LoginStatus ID="LoginStatus1" runat="server" />
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

Login.aspx


<%@ Page Title="" Language="C#" MasterPageFile="Site1.Master" %>
<%@ Import Namespace="CustomAuthRepurposingFormsAuth" %>
<script runat="server">

    /*
     * If you don't want to use a custom membership provider to authenticate
     * simply place your logic in the login control's handler and remove the 
     * membership element from config. It would have to take a very very 
     * compelling edge case to motivate me to not use a custom membership provider.
     * 
     */

    //protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    //{
    //    // perform mindbendingly complex authentication logic
    //    e.Authenticated = Login1.UserName == Login1.Password;
    //}


    /*
     * set your cookie and you are golden
     */
    void Authenticated(object sender, EventArgs e)
    {
        // this is an arbitrary data slot you can use for ???
        // keep cookie size in mind when using it.
        string userData = "arbitraryData";
        Response.Cookies.Add(TicketHelper.CreateAuthCookie(Login1.UserName, userData, Login1.RememberMeSet /*persistent cookie*/));
    }

</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <asp:Login ID="Login1" runat="server" OnLoggedIn="Authenticated" >
    </asp:Login>
    username==password==authenticated. <br />e.g.: uid: me, pwd:me
</asp:Content>

Default.aspx


<%@ Page Title="" Language="C#" MasterPageFile="Site1.Master" %>

<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="CustomAuthRepurposingFormsAuth" %>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        /*
         * you get this for free from asp.net
         */

        HttpContext page = HttpContext.Current;

        IIdentity identity = page.User.Identity;
        string username = identity.Name;
        bool authenticate = identity.IsAuthenticated;
        // or use the Request.IsAuthenticated convenience accessor

        /* 
         * you get this really cheap from forms auth
         * 
         * cost: validating credentials and setting your own ticket
         */

        // this page is protected by formsauth so the identity will actually 
        // be a FormsIdentity and you can get at the user data.
        // UserData is an appropriate place to store _small_ amounts of data
        var fIdent = (FormsIdentity)identity;
        string userData = fIdent.Ticket.UserData;


        // so, using only forms auth this is what you have to work with
        LblAuthenticated.Text = page.User.Identity.IsAuthenticated.ToString();
        LblUserId.Text = page.User.Identity.Name;
        LblUserData.Text = userData;

        /* 
         * this is an example of using a custom membership provider and subclassing the 
         * MembershipUser class to take advantage of the established mature infrastructure
         * 
         * this is entirely optional, you can delete the Membership section in web.config 
         * and delete MyMembershipProvider and MyMembershipUser and just use the authentication.
         * 
         */

        // get the custom field
        string myCustomField = ((MyMembershipUser)Membership.GetUser()).MyCustomField;
        LblMembership.Text = myCustomField;
    }        
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <br />
    Authenticated:<asp:Label ID="LblAuthenticated" runat="server" Text=""></asp:Label><br />
    UserId:<asp:Label ID="LblUserId" runat="server" Text=""></asp:Label><br />
    UserData:<asp:Label ID="LblUserData" runat="server" Text=""></asp:Label><br />
    <br />
    Membership User Custom Field:<asp:Label ID="LblMembership" runat="server" Text=""></asp:Label><br />
</asp:Content>

CustomAuthClasses.cs


using System;
using System.Web;
using System.Web.Security;

namespace CustomAuthRepurposingFormsAuth
{
    public static class TicketHelper
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="userData">be mindful of the cookie size or you will be chasing ghosts</param>
        /// <param name="persistent"></param>
        /// <returns></returns>
        public static HttpCookie CreateAuthCookie(string userName, string userData, bool persistent)
        {
            DateTime issued = DateTime.Now;
            // formsAuth does not expose timeout!? have to hack around the
            // spoiled parts and keep moving..
            HttpCookie fooCookie = FormsAuthentication.GetAuthCookie("foo", true);
            int formsTimeout = Convert.ToInt32((fooCookie.Expires - DateTime.Now).TotalMinutes);

            DateTime expiration = DateTime.Now.AddMinutes(formsTimeout);
            string cookiePath = FormsAuthentication.FormsCookiePath;

            var ticket = new FormsAuthenticationTicket(0, userName, issued, expiration, true, userData, cookiePath);
            return CreateAuthCookie(ticket, expiration, persistent);
        }

        public static HttpCookie CreateAuthCookie(FormsAuthenticationTicket ticket, DateTime expiration, bool persistent)
        {
            string creamyFilling = FormsAuthentication.Encrypt(ticket);
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, creamyFilling)
                             {
                                 Domain = FormsAuthentication.CookieDomain,
                                 Path = FormsAuthentication.FormsCookiePath
                             };
            if (persistent)
            {
                cookie.Expires = expiration;
            }

            return cookie;
        }
    }

    /// <summary>
    /// This is an example of inheriting MembershipUser to
    /// expose arbitrary data that may be associated with your
    /// user implementation.
    /// 
    /// You may repurpose existing fields on the base and add your own.
    /// Just perform a cast on the MembershipUser returned from your
    /// MembershipProvider implementation
    /// </summary>
    public class MyMembershipUser : MembershipUser
    {
        public MyMembershipUser(string providerName, string name, object providerUserKey, string email,
                                string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
                                DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate,
                                DateTime lastPasswordChangedDate, DateTime lastLockoutDate)
            : base(
                providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut,
                creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate)
        {
        }

        protected MyMembershipUser()
        {
        }

        // e.g. no desire to use Profile, can just add data
        // say, from a flat record containing all user data
        public string MyCustomField { get; set; }
    }

    /// <summary>
    /// At the most basic level, implementing a MembershipProvider allows you to
    /// reuse established framework code. In this case, we just provide services
    /// for the Login control and user identification via Membership subsystem.
    /// </summary>
    public class MyMembershipProvider : MembershipProvider
    {
        #region Minimum implementation in order to use established authentication and identification infrastructure

        /// <summary>
        /// You can just do this in the login logic if you do not want
        /// leverage framework for membership user access
        /// </summary>
        public override bool ValidateUser(string username, string password)
        {
            return username == password;
        }


        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            /*
             * Simulate going to the DB to get the data
             */

            // membership user non nullable fields, repurpose or use
            // implied null value e.g DateTime.MinValue;

            var createdDate = new DateTime(2009, 10, 25);
            var lastLogin = new DateTime(2009, 10, 25);
            var lastActivity = new DateTime(2009, 10, 25);
            var lastPasswordChange = new DateTime(2009, 10, 25);
            var lastLockoutDate = new DateTime(2009, 10, 25);

            object providerUserKey = 3948; // e.g. user primary key. 


            /*
             * build your custom user and send it back to asp.net
             */

            // need to use the full constructor to set the username and key
            var user = new MyMembershipUser(Name, username, providerUserKey, null, null, null, true, false, createdDate,
                                            lastLogin,
                                            lastActivity, lastPasswordChange, lastLockoutDate)
                           {
                               MyCustomField = "Hey"
                           };

            return user;
        }

        #endregion

        #region Optional implementations depending on the framework features you would like to leverage.

        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); }
        }

        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }

        public override string ApplicationName
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }


        public override MembershipUser CreateUser(string username, string password, string email,
                                                  string passwordQuestion, string passwordAnswer, bool isApproved,
                                                  object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password,
                                                             string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }


        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
                                                                 out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
                                                                  out int totalRecords)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

Solution actually used (in as ASP.NET MVC project using OpenID):

I have an AccountController which I use to log users in and out and these methods are there.

#region Methods to log in a user.
/// <summary>
/// Create the auth cookie in the same way it is created my ASP.NET Membership system, hopefully lasting for more than 20 minutes.
/// 
/// For more information check out http://stackoverflow.com/questions/2122831/is-it-possible-to-use-aspxauth-for-my-own-logging-system
/// </summary>
/// <param name="userId">Id of the user that is logged in</param>
/// <returns>Cookie created to mark the user as authenticated.</returns>
private static HttpCookie CreateAuthCookie(int userId) {
  DateTime issued = DateTime.Now;
  // formsAuth does not expose timeout!? have to hack around the spoiled parts and keep moving..
  HttpCookie fooCookie = FormsAuthentication.GetAuthCookie("foo", true);
  int formsTimeout = Convert.ToInt32((fooCookie.Expires - DateTime.Now).TotalMinutes);

  DateTime expiration = DateTime.Now.AddMinutes(formsTimeout);

  var ticket = new FormsAuthenticationTicket(0, userId.ToString(), issued, expiration, true, "", FormsAuthentication.FormsCookiePath);
  return CreateAuthCookie(ticket, expiration, true);
}

/// <summary>
/// Create an auth cookie with the ticket data.
/// </summary>
/// <param name="ticket">Ticket containing the data to mark a user as authenticated.</param>
/// <param name="expiration">Expriation date for the cookie.</param>
/// <param name="persistent">Whether it's persistent or not.</param>
/// <returns>Cookie created to mark the user as authenticated.</returns>
private static HttpCookie CreateAuthCookie(FormsAuthenticationTicket ticket, DateTime expiration, bool persistent) {
  string encryptedAuthData = FormsAuthentication.Encrypt(ticket);
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedAuthData) {
    Domain = FormsAuthentication.CookieDomain,
    Path = FormsAuthentication.FormsCookiePath
  };
  if (persistent) {
    cookie.Expires = expiration;
  }

  return cookie;
}

/// <summary>
/// Expire the authentication cookie effectively loging out a user.
/// </summary>
private void ExpireAuthCookie() {
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
  cookie.Expires = DateTime.Now.AddDays(-1);
  Response.Cookies.Add(cookie);
}
#endregion
街道布景 2024-08-26 03:07:39

ASPXAUTH cookie 将身份验证令牌与会话完全分开,这是使用它的原因之一。如果您的系统使用会话,那么它与表单身份验证尝试执行的操作确实不一致。

如果一切都在会话中,那么假设会话是安全的,那么实际上您根本不需要身份验证票证。

The ASPXAUTH cookie separates the authentication token from the session entirely, it's one of the reasons it's used. If your system uses session then it's really at odds with what forms authentication is trying to do.

If everything is in a session then really you don't need the authentication ticket at all, assuming the session is secured.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文