5

我有一个使用 asp.net 登录控件的 Web 应用程序。此外,我还为用户使用了密码恢复控件来恢复他们的密码。一旦用户在恢复控件中输入了他们的详细信息,一封包含验证 URL 的电子邮件将被发送到用户的电子邮件地址。单击 URL 后,它将引导用户进入我的 Web 应用程序的 UserProfile,其中允许用户更改密码。

现在的问题是,因为我对 UserProfile.aspx 设置了访问规则以拒绝匿名用户,所以当我从 URL 重定向到 UserProfile.aspx 页面时,它会将我定向到 LoginPage(系统将我识别为匿名用户)。

为什么会这样?单击 URL(包括所有用户信息)后,是否有任何地方可以直接进入用户配置文件页面?

URL 如下所示:

http://localhost:1039/Members/UserProfile.aspx?ID=56f74cc7-7680-4f1b-9207-0ab8dad63cad 

URL 的最后一部分实际上是 userId。

这是用户配置文件 aspx 的代码:

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
              ConnectionString="<%$ ConnectionStrings:ASPNETDBConnectionString1 %>" 
              SelectCommand="SELECT aspnet_Membership.Email, Details.CustName, Details.CustNum, Details.CustRole, Details.CustStatus, Details.PName, Details.PEmail, Details.PRole, Details.WedDate, aspnet_Users.UserName, Details.UserId FROM Details INNER JOIN aspnet_Membership ON Details.UserId = aspnet_Membership.UserId INNER JOIN aspnet_Users ON aspnet_Membership.UserId = aspnet_Users.UserId WHERE (Details.UserId = @UserId)" 


              UpdateCommand="update Details SET CustName = @CustName, CustNum = @CustNum, CustRole = @CustRole, CustStatus = @CustStatus, PName = @PName, PEmail = @PEmail, PRole = @PRole, WedDate = @WedDate WHERE [UserId] = @UserId

                            Update aspnet_Membership Set Email= @email WHERE [UserId] = @UserId"

              DeleteCommand= "DELETE FROM Details WHERE UserId = @UserId;"> 

              <DeleteParameters>
                  <asp:ControlParameter ControlID="lblHidden" Name="UserId" PropertyName="Text" 
                      Type="String" />
              </DeleteParameters>

              <SelectParameters>
                  <asp:ControlParameter ControlID="lblHidden" Name="UserId" PropertyName="Text" />

              </SelectParameters>

              <UpdateParameters>
                  <asp:Parameter Name="CustName" />
                  <asp:Parameter Name="CustNum" />
                  <asp:Parameter Name="CustRole" />
                  <asp:Parameter Name="CustStatus" />
                  <asp:Parameter Name="PName" />
                  <asp:Parameter Name="PEmail" />
                  <asp:Parameter Name="PRole" />
                  <asp:Parameter Name="WedDate" />
                  <asp:Parameter Name="UserId" />
                  <asp:Parameter Name="email" />
              </UpdateParameters>


          </asp:SqlDataSource>
          <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" 
              DataSourceID="SqlDataSource1" Height="50px" Width="125px">
              <Fields>
                  <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
                  <asp:BoundField DataField="CustName" HeaderText="CustName" 
                      SortExpression="CustName" />
                  <asp:BoundField DataField="CustNum" HeaderText="CustNum" 
                      SortExpression="CustNum" />
                  <asp:BoundField DataField="CustRole" HeaderText="CustRole" 
                      SortExpression="CustRole" />
                  <asp:BoundField DataField="CustStatus" HeaderText="CustStatus" 
                      SortExpression="CustStatus" />
                  <asp:BoundField DataField="PName" HeaderText="PName" SortExpression="PName" />
                  <asp:BoundField DataField="PEmail" HeaderText="PEmail" 
                      SortExpression="PEmail" />
                  <asp:BoundField DataField="PRole" HeaderText="PRole" SortExpression="PRole" />
                  <asp:BoundField DataField="WedDate" HeaderText="WedDate" 
                      SortExpression="WedDate" />
                  <asp:BoundField DataField="UserName" HeaderText="UserName" 
                      SortExpression="UserName" />
                  <asp:BoundField DataField="UserId" HeaderText="UserId" 
                      SortExpression="UserId" />
                  <asp:CommandField ShowEditButton="True" />
              </Fields>
          </asp:DetailsView>
          <asp:Label ID="lblHidden" runat="server" Text="Label" Visible="False"></asp:Label>



          <asp:Button ID="btnDelete" runat="server" onclick="btnDelete_Click" 
              Text="Delete" />

这是后面的代码:

protected void Page_Load(object sender, EventArgs e)
    {
         MembershipUser currentUser = Membership.GetUser();
        lblHidden.Text = currentUser.ProviderUserKey.ToString();
    }

    protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
    {
        // Get a reference to the currently logged on user
        MembershipUser currentUser = Membership.GetUser();

        // Determine the currently logged on user's UserId value
        // Assign the currently logged on user's UserId to the @UserId parameter
        //access the parameter value using e.Command.Parameters 
        //programmatically set the @UserId:
        e.Command.Parameters["@UserId"].Value = currentUser.ProviderUserKey.ToString();



    }
    protected void btnDelete_Click(object sender, EventArgs e)
    {

        SqlConnection connection = new SqlConnection();
        connection.ConnectionString = ConfigurationManager.ConnectionStrings["ASPNETDBConnectionString1"].ConnectionString;
        SqlCommand cmd = new SqlCommand();
        SqlCommand cmd1 = new SqlCommand(); 
        string userId = lblHidden.Text;

        cmd.Connection = connection;
        cmd.CommandText = "DELETE FROM Details WHERE UserId ='" + userId + "'";


        cmd1.Connection = connection;
        cmd1.CommandText = "DELETE FROM aspnet_Membership WHERE UserId ='" + userId + "'"; 

        connection.Open();

        cmd.ExecuteNonQuery();
        cmd1.ExecuteNonQuery();


        connection.Close();


      Response.Redirect("Home.aspx");
    }

其次,有什么办法可以设置 URL 的过期时间吗?如果 URL 被第二次点击,它不会将用户重定向到任何地方。我看到很多帖子,其中大多数建议在数据库中添加一列。有没有其他方法可以在不接触数据库的情况下设置到期时间???

4

3 回答 3

5

考虑更改密码链接的单独页面。让此页面采用唯一标识符。这个标识符应该只工作一次,有一个到期日期,并且是特定于该用户的。将此页面设为公开:

<location path="changepassword.aspx">
 <system.web>
   <authorization>
     <allow users="*"/>
   </authorization>
 </system.web>
</location>

您需要在某处针对用户存储唯一标识符。如果您不想影响当前架构,可以创建一个新表:

PK | Identifier | UserID                               | expires
1  | abcd       | ffffffff-ffff-ffff-ffff-ffffffffffff | 16-jul-2012 18:26

当请求页面时,如果标识符已过期,则不允许该页面运行。更改密码后,使标识符无效 - 要么将其删除,要么将过期日期设置为过去的某个时间(例如现在)。

于 2012-07-16T16:26:14.497 回答
2

这不是对所提出问题的直接回应,而是对构建密码重置工具的更一般的评论......

在编写此功能时,我会做一些不同的事情。

访问个人资料页面或只是更改密码?

首先,如果用户只需要更改他们的密码,他们不需要访问用户个人资料页面,只需更改密码页面即可。我会将他们直接带到“更改密码”页面,并使其特定于密码重置功能,因此可以毫无问题地匿名使用。

为什么不对它们进行身份验证,然后将它们发送到个人资料页面?

另一种选择是不要乱用匿名访问事物,只需执行自动登录即可。该 url 将指向一个登录页面,该页面将自动登录给定的用户(毕竟您拥有所有用户详细信息)。然后他们可以被重定向到个人资料页面,他们不再是匿名的,所以一切都很好。

纯文本用户 ID 的问题

您需要使用更好的令牌。如果有人可以找到另一个用户的用户 ID(如果您单击以查看用户的公共个人资料,它可能会显示在 url 中),那么他们可以更改该人的密码。我相信你知道这并不酷。

我用什么代替纯文本用户 ID?

随机令牌

围绕此的两种方法是创建存储在数据库中的随机令牌,然后在加载页面时验证它们。当然,当您想要使它们无效时,只需更改数据库中的某些内容,就可以很容易地使它们无效。您可以在数据库中存储一个随机令牌(我可能会选择一个大约 16 个字符长的 base64 编码字符串 - 实际上是 96 位随机性)以及任何必要的信息(例如用户 ID、创建日期(或到期日期)) , ETC。)。如果您希望它成为一种用途,您可以在验证一次后将令牌从数据库中清除(或标记一个字段以说明其已被使用或任何数量的其他替代方案)。

加密令牌

不涉及接触数据库的更安全的方法是创建一个可以传递给用户的加密令牌。该令牌可能包含用户 ID 和创建令牌的时间(以及您喜欢的任何其他信息),并且会被放入电子邮件中并被遗忘。因为它是加密数据而不是回发时的随机令牌,而不是通过数据库进行验证,所以您可以解密给定的令牌以查找用户以及令牌的年龄。

如果您想在不访问数据库的情况下使它们成为一种用途,这有点棘手,但我可能会将生成的令牌存储在服务器应用程序字典中,如果令牌不在其中,则它无效并且您删除一旦使用,它就从您存储的列表中。您还定期清理旧令牌,以确保您没有存储太多垃圾。这种方法还有一个缺点,即如果重新启动应用程序,您将清除令牌列表,从而使它们全部失效。这只是一个问题,如果你需要它们是一个镜头。就个人而言,我会让他们在您确定适合使用单个令牌的任何时间范围内随心所欲地重置密码。:)

原始场景中关于明文用户 ID 的另一个警告

我不能强调你需要多么小心,只需将用户 ID 以纯文本形式放在 url 中作为唯一传递的信息。当有人发现另一个人的用户 ID 时,他们的帐户就被有效地入侵了。他们只需要将那个人的用户 ID 放入 url 中,他们就可以更改他们的密码。

即使您现在没有任何地方可以公开其他人的 UserID,您也必须 100% 确定将来永远不会,这在实践中是无法保证的。

于 2012-07-16T16:35:27.257 回答
1

<configuration>您可以通过将以下内容添加到标签内的 web.config 来尝试允许匿名用户进入您的用户配置文件页面。

  <location path="userProfile.aspx">
    <system.web>
      <authorization>
        <allow users="?"/>
      </authorization>
    </system.web>
  </location>
于 2012-07-16T16:20:43.770 回答