2012-07-16 121 views
5

我有一個使用asp.net登錄控件的web應用程序。另外,我還使用密碼恢復控制讓用戶恢復密碼。一旦用戶在恢復控制中輸入了他們的詳細信息,包含驗證URL的電子郵件將發送到用戶的電子郵件地址。點擊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的最後一部分實際上是用戶ID。

這裏是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,則不會將用戶重定向到任何地方。我看到很多帖子,他們中的大多數人建議在數據庫中添加一列。有沒有其他方式可以在不觸碰數據庫的情況下設置到期日?

+0

你是否在你的應用中創建了角色? – 2012-07-16 16:25:16

+0

嗨,我沒有在.Net配置中創建任何角色。 – user1529419 2012-07-17 03:21:45

回答

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 

當被請求的頁面,如果標識符已過期不允許頁面的功能。密碼更改後,使標識符無效 - 將其刪除,或將過期日期設置爲過去的某個時間(例如,現在)。

+0

嗨,謝謝你的回覆。從下面的Chris的帖子 - 「爲什麼不驗證他們,然後將他們發送到個人資料頁?」 這就是我目前使用的。一旦用戶點擊URL,系統應該自動認證用戶,這就是爲什麼他們可以進入UserProfile.aspx(沒有訪問規則的問題)。 但是我怎樣才能讓用戶使用asp.net登錄控件自動登錄? – user1529419 2012-07-17 04:45:29

+0

@ user1529419。只要你使用UserID來識別用戶,你可以讓任何人改變任何人的密碼(正如Chris所說的那樣「不酷」)。我建議你在UserProfile.aspx頁面上維護身份驗證。它具有「更改密碼」的不同目的。 – 2012-07-17 08:24:14

1

您可以嘗試通過將以下內容添加到<configuration>標記中的web.config中來允許匿名用戶進入您的用戶配置文件頁面。

<location path="userProfile.aspx"> 
    <system.web> 
     <authorization> 
     <allow users="?"/> 
     </authorization> 
    </system.web> 
    </location> 
+0

如果我沒有錯,那麼這個條件將允許任何人訪問該頁面?糾正我請 – 2012-07-16 16:29:11

+0

@waqar。有必要允許所有用戶,因爲用戶可以通過「重置密碼」電子郵件鏈接訪問。查看我的答案以獲得更安全的方法。 – 2012-07-16 16:33:00

+0

@flem您的回答是正確的bcz您允許所有用戶使用changepasswordpage,但sam允許所有用戶使用UserProfilePage。 – 2012-07-16 16:37:30

2

這並不是問題,但問結構上的密碼重置工具更普遍的意見的直接回應...

當編碼這個功能我做了幾個不同的事情。

進入配置文件頁面或只是更改密碼?

首先,如果用戶只是需要更改密碼,他們不需要訪問用戶配置文件頁面,只需更改密碼頁面。我會直接將它們帶到「更改密碼」頁面,並將其專用於密碼重置功能,從而以匿名方式提供,而不會出現任何問題。

爲什麼不驗證它們,然後將它們發送到配置文件頁面?

另一種選擇是,而不是亂用匿名訪問的東西只是做一個自動登錄。該網址會導致登錄頁面自動記錄給定的用戶(畢竟您擁有所有的用戶詳細信息)。然後,他們可以重定向到個人資料頁面,他們不再是匿名的,所以它們都很好。

純文本的用戶ID

您需要使用更好的令牌問題。如果有人可以找到另一個用戶的用戶名(如果你點擊查看用戶的公開個人資料,可能會顯示在url中),那麼他們可以更改該人的密碼。這不是很酷,因爲我確信你知道。

我該用什麼來代替明文用戶ID?

隨機令牌

解決這個問題的兩種方法創建你存儲在數據庫中,然後驗證它們加載頁面時,隨機令牌。當然,當你想使它們失效時,只需要改變數據庫中的某些東西就可以很容易地使它們失效。您可以隨意存儲一個隨機標記(我可能會使用base64編碼的字符串,長度大約爲16個字符 - 有效的96位隨機數)以及任何必需的信息(例如用戶標識符,創建日期(或有效日期)等)。如果你希望它成爲一個用途,你可以在數據庫被驗證一次(或者標記一個字段來表明它已被使用或者其他任何數量的選擇)之後清除該數據庫中的令牌。

加密令牌

不涉及觸摸數據庫是創建一個可以傳遞給用戶的加密令牌更安全的方法。此令牌可能包含用戶ID和創建令牌的時間(以及您感興趣的任何其他信息),並將放入電子郵件中並被忘記。因爲它是加密的數據而不是通過回發中的隨機令牌,而不是通過數據庫驗證,所以您可以解密給定的令牌來找出用戶以及令牌的年齡。

如果你想讓它們在沒有觸及數據庫的情況下使用它,它會更棘手一點,但我可能會將生成的令牌存儲在服務器應用程序字典中,如果令牌不在其中,有效,並將其從您存儲的列表中刪除。您還經常清理舊的令牌,以確保您不會存儲太多的垃圾。這種方法也有缺點,如果應用程序重新啓動,你會清除令牌列表,從而使它們全部無效。這只是一個問題,如果你需要他們成爲一杆。就我個人而言,我會讓他們在任何時間範圍內重新設置他們想要的密碼,只要使用一個令牌即可。 :)

有關原始方案

明文用戶ID的另外一個問題,你需要多小心與只是把用戶ID以純文本的URL作爲傳遞的唯一信息,我不能強調不夠。有人發現另一個人的用戶ID的時候,他們的帳戶被有效地破壞了。他們只需要將該用戶的userid放入url中,並且可以更改密碼。

即使您現在沒有任何公開其他人的用戶ID的地方,您必須100%確定您將來永遠不會在實踐中無法保證的地方。