我有一个使用asp.net登录控件的web应用程序。此外,我还为用户使用了密码恢复控件来恢复他们的密码。一旦用户在恢复控制中输入了他们的详细信息,就会向用户的电子邮件地址发送一封包含验证URL的电子邮件。单击网址后,它会将用户定向到我的web应用程序的UserProfile,在该URL中,它允许用户更改其密码。
现在的问题是,因为我为UserProfile.aspx设置了拒绝匿名用户的访问规则,所以当我从URL重定向到UserProfile.aspx页面时,它会将我定向到LoginPage (系统将我识别为匿名用户)。
为甚麽呢?单击URL (包括所有用户信息)后,是否有任何地方可以直接进入用户配置文件页面?
URL如下所示:
http://localhost:1039/Members/UserProfile.aspx?ID=56f74cc7-7680-4f1b-9207-0ab8dad63cad 其中URL的最后一部分实际上是userId。
以下是userprofile 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,则不会将用户重定向到任何位置。我看过很多帖子,其中大多数都建议在数据库中添加一列。有没有其他方法可以在不接触数据库的情况下设置过期时间?
发布于 2012-07-17 00:26:14
考虑为changepassword链接创建一个单独的页面。让此页采用唯一标识符。此标识符应只工作一次,具有到期日期,并且特定于该用户。使此页面公开:
<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-17 00:35:27
这不是对所问问题的直接回答,而是对构建密码重置工具的更一般的评论……
在编写此功能时,我会做一些不同的事情。
使用访问配置文件页面,还是只更改密码?
首先,如果用户只需要更改密码,他们不需要访问用户配置文件页面,只需要访问更改密码页面。我会将他们直接带到“更改密码”页面,并将其指定为密码重置功能,从而使其匿名可用,没有任何问题。
为什么不对它们进行身份验证,然后将它们发送到配置文件页面?
另一种选择是,不要浪费时间进行匿名访问,只需自动登录即可。该url将指向一个登录页面,该页面将自动登录给定的用户(毕竟您拥有所有的用户详细信息)。然后他们可以被重定向到个人资料页面,他们不再是匿名的,所以一切都很好。
使用纯文本用户ids解决问题
您需要使用更好的令牌。如果有人可以找到另一个用户的用户id (如果您单击查看用户的公共配置文件,它可能会显示在url中),那么他们就可以更改该用户的密码。这并不酷,因为我相信你知道。
我应该使用什么而不是纯文本用户I?
随机令牌
围绕这一点的两种方法是创建随机令牌,将其存储在数据库中,然后在加载页面时对其进行验证。当然,这使得当您想要使它们无效时,只需更改数据库中的某些内容就可以非常容易地使它们无效。你可以在数据库中存储一个随机的令牌(我可能会选择一个base64编码的字符串,长度大约是16个字符--相当于96位的随机性)以及任何必要的信息(例如用户‘d、创建日期(或过期日期)等)。如果你想让它只使用一次,你只需要在它被验证一次之后就把它从数据库中清除掉(或者标记一个字段来说明它已经被使用过或者其他任何数量的替换)。
加密令牌
不涉及数据库的更安全的方法是创建一个可以传递给用户的加密令牌。此令牌可以包含userID和创建令牌的时间(以及您想要的任何其他信息),并将放在电子邮件中并被遗忘。因为它是加密的数据,而不是回发时的随机令牌,而不是通过数据库验证,所以您可以只解密给定的令牌,以fidn用户和令牌的年龄。
如果你想让它们在不访问数据库的情况下一次性使用,这会有点棘手,但我可能会选择将生成的令牌存储在服务器应用程序字典中,如果令牌不在那里,它就是无效的,一旦它被使用,你就将它从存储的列表中删除。您还会定期清理旧令牌,以确保不会存储太多垃圾。这种方法也有一个缺点,即如果应用程序重启,您将清除令牌列表,从而使它们全部失效。这只是一个问题,如果你需要它们是一次拍摄。就我个人而言,我会让他们在任何时间段内用一个令牌重置他们想要的密码。:)
有关原始方案中的明文用户ID的另一个警告
我再怎么强调也不为过,你需要非常小心地将用户标识以明文的形式放在url中作为唯一传递的信息。一旦有人发现另一个人的userID,他们的账户实际上就被攻破了。他们只需在url中输入用户and,他们就可以更改密码。
即使您现在没有公开其他人的UserIDs的地方,您也必须100%地确定将来也不会这样做,这在实践中是不可能保证的。
发布于 2012-07-17 00:20:44
您可以尝试允许匿名用户进入您的用户配置文件页面,方法是将以下内容添加到<configuration>标记内的web.config中。
<location path="userProfile.aspx">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>https://stackoverflow.com/questions/11508324
复制相似问题