2017-07-21 93 views
0

我創建了一個機制,增加結​​束時間鎖定基於有多少時間在用戶輸入了錯誤的密碼鎖定結束時間如何顯示在asp.net MVC5

case SignInStatus.LockedOut: 
{ 
    if (failedAttempt > 0) 
    { 
     user.LockoutEnabled = true; 
     user.LockoutEndDateUtc = DateTime.UtcNow.AddMinutes(5* failedAttempt); 
     await UserManager.UpdateAsync(user); 
    } 
    return View("Lockout"); 
} 

我想展示對於鎖定視圖中的用戶:

@model System.Web.Mvc.HandleErrorInfo 
@{ 
    ViewBag.Title = "locked"; 
} 

<hgroup> 
    <h1 class="text-danger">Verrouillé.</h1> 
    <h2 class="text-danger">Ce compte a été verrouillé, veuillez réessayer./h2> 
</hgroup> 

該怎麼做?

謝謝

回答

1

如果您按照您的方案,當用戶無效它只decresases您的無效嘗試。它不會實際掛起用戶,除非他們正確輸入登錄憑證。

真的是你的sudo的邏輯應該去:

  • 驗證憑據
  • 證書有效
  • 檢查帳戶狀態,被暫停則拒絕訪問
  • 重置嘗試回到5
  • 允許用戶進入應用程序
  • 憑證無效
  • 由一個
  • 設定帳戶減少企圖懸浮如果此邏輯的需要

潤通可以真正被綁定到一個或兩個方法。同樣在你的DecreaseAttempts()方法中,你有兩個SQL命令,其中sql命令cmd永遠不會執行

這是一個在一個方法中返回枚舉狀態的例子。現在這是一個非常基本的例子,但只需要一種方法來執行完整的授權方法。我已經評論過代碼。

public partial class UserManager 
{ 

    const int MaxAttempts = 5; 

    public LoginStatus ValidateUser(string username, string password) 
    { 
     if (string.IsNullOrWhiteSpace(username)) 
      throw new ArgumentNullException("username"); 

     //set the password to empty if it is null 
     password = password ?? ""; 

     //create the connection 
     using (var connection = new SqlConnection(Configuration.ConnectionString)) 
     { 
      //assign some local variables 
      int attemptsLeft = MaxAttempts; 
      string currentStatus = "Active"; 
      string userPassword = null; 

      //get the information for the user, only query by username so we have all the data. We will match the password later on 
      string query = "SELECT TOP(1) [Username], [Password], [AttemptsLeft], [CurrentStatus] FROM [Information] WHERE Username = @username"; 

      using (var command = new SqlCommand(query, connection)) 
      { 
       command.Parameters.AddWithValue("@username", username); 
       command.CommandType = System.Data.CommandType.Text; 

       connection.Open(); 

       using (var reader = command.ExecuteReader()) 
       { 
        //no rows.. Invalid username 
        if (!reader.HasRows) 
        { 
         connection.Close(); 
         return LoginStatus.InvalidCredentials; 
        } 

        //read the first row (hence the break) 
        while (reader.Read()) 
        { 
         attemptsLeft = (int)reader["AttemptsLeft"]; 
         currentStatus = (string)reader["CurrentStatus"]; 
         userPassword = (string)reader["Password"]; 
         break; 
        } 
        reader.Close(); 
       } 
       connection.Close(); 
      } 

      //if the account is suspended then dont even bother with password checking 
      if (currentStatus.Equals("Suspended", StringComparison.CurrentCultureIgnoreCase)) 
      { 
       return LoginStatus.Suspended; 
      } 

      //invalid password lets handle the invalid credentials logic 
      if (!password.Equals(userPassword)) 
      { 
       attemptsLeft -= 1; 

       //decrease the attempts, lets just stop at zero as we dont need negative attempts 
       if(attemptsLeft >= 0) 
       { 
        query = "UPDATE [Information] SET [AttemptsLeft] = @attemptsLeft WHERE Username = @username"; 
        using (var command = new SqlCommand(query, connection)) 
        { 
         command.Parameters.AddWithValue("@username", username); 
         command.Parameters.AddWithValue("@attemptsLeft", attemptsLeft); 
         connection.Open(); 
         command.ExecuteNonQuery(); 
         connection.Close(); 
        } 
       } 

       //suspend the account when attempts less than or equal to zero 
       if (attemptsLeft <= 0) 
       { 
        query = "UPDATE [Information] SET [CurrentStatus] = @currentStatus WHERE Username = @username"; 
        using (var command = new SqlCommand(query, connection)) 
        { 
         command.Parameters.AddWithValue("@username", username); 
         command.Parameters.AddWithValue("@currentStatus", "Suspended"); 
         connection.Open(); 
         command.ExecuteNonQuery(); 
         connection.Close(); 
        } 
        //exit method as login account suspended 
        return LoginStatus.Suspended; 
       } 

       //exit as invalid login credentials 
       return LoginStatus.InvalidCredentials; 
      } 
      //if we are here lets quickly reset the login attempts back to 5, and account status to active as this is a valid login 
      query = "UPDATE [Information] SET [AttemptsLeft] = @attemptsLeft, [CurrentStatus] = @currentStatus WHERE Username = @username"; 
      using (var command = new SqlCommand(query, connection)) 
      { 
       command.Parameters.AddWithValue("@username", username); 
       command.Parameters.AddWithValue("@attemptsLeft", MaxAttempts); 
       command.Parameters.AddWithValue("@currentStatus", "Active"); 
       connection.Open(); 
       command.ExecuteNonQuery(); 
       connection.Close(); 
      } 
      //if we got here then every thing is a match 
      return LoginStatus.Authorized; 
     } 
    } 

} 

public enum LoginStatus 
{ 
    Authorized, 
    InvalidCredentials, 
    Suspended 
} 

要使用這可能是如下那樣簡單(注意,您必須更改視圖重定向)

[HttpPost] 
public ActionResult Index(string username, string password) 
{ 
    if(string.IsNullOrWhiteSpace(username)) 
    { 
     this.ModelState.AddModelError("", "Invalid Login Credential. No username sent."); 
     return View(); 
    } 

    var manager = new UserManager(); 

    var result = manager.ValidateUser(username, password); 

    switch (result) 
    { 
     case LoginStatus.Authorized: 
      return RedirectToAction("About", "Home"); 

     case LoginStatus.InvalidCredentials: 
      this.ModelState.AddModelError("", "Invalid Login Credentials. Username or password incorrect"); 
      break; 

     case LoginStatus.Suspended: 
      this.ModelState.AddModelError("", "Account Suspeneded"); 
      break; 
    } 

    return View(); 
} 

只是爲了好玩我改寫成一個簡單的存儲過程這一點。

CREATE PROCEDURE ValidateUser 
    @username nvarchar(50), 
    @password nvarchar(50) 
AS 
BEGIN 

    SET NOCOUNT ON; 

    DECLARE @userPassword nvarchar(50) = NULL 
    DECLARE @maxAttempts int = 5 
    DECLARE @attemptsLeft int = 5 
    DECLARE @currentStatus nvarchar(50) 

    /* 
     RETURN CODES: 
     0 = Authorized 
     1 = InvalidCredentials 
     2 = Suspended 
    */ 


    SELECT TOP(1) @userPassword = [UserName], @attemptsLeft = [AttemptsLeft], @currentStatus = [CurrentStatus] FROM [Information] WHERE UserName = @username 

    IF @userPassword IS NULL 
     BEGIN 
      SELECT 1 as [Result], @maxAttempts as [AttemptsRemaining] 
      RETURN 
     END 

    --account suspended.. Return a suspended result 
    If @currentStatus = 'Suspended' 
     BEGIN 
      SELECT 2 as [Result], 0 as [AttemptsRemaining] 
      RETURN 
     END 

    --passwords dont match (note this is case insensitive on default collation) 
    If @password IS NULL OR @password <> @userPassword 
     BEGIN 
      --decrease attempts 
      SET @attemptsLeft = @attemptsLeft - 1 

      --if the attempts left are greater than 0 then set the account active and decrease the attempts remaining 
      IF @attemptsLeft > 0 
       BEGIN 
        UPDATE [Information] SET [CurrentStatus] = 'Active', AttemptsLeft = @attemptsLeft WHERE UserName = @username 
        SELECT 1 as [Result], @attemptsLeft as [AttemptsRemaining] 
        RETURN 
       END 
      --else the attempts left are less than or equal to zero therefore they should be suspended and attempts left set to zero (dont want negative attempts) 
      ELSE 
       BEGIN 
        UPDATE [Information] SET [CurrentStatus] = 'Suspended', AttemptsLeft = 0 WHERE UserName = @username 
        SELECT 2 as [Result], 0 as [AttemptsRemaining] 
        RETURN 
       END 
     END 
    --if we get here then all is good and we can just reset the account status and max attempts for the next login attempt 
    UPDATE [Information] SET [CurrentStatus] = 'Active', AttemptsLeft = @maxAttempts WHERE UserName = @username 
    SELECT 0 as [Result], @maxAttempts AS [AttemptsRemaining] 

END 
GO 

然後調用這是非常簡單的(注意我也已經改變了返回類型,返回兩個狀態和剩餘發起呼叫。

方法

public LoginResult ValidateUserStoredProcedure(string username, string password) 
{ 
    if (string.IsNullOrWhiteSpace(username)) 
     throw new ArgumentNullException("username"); 

    //set the password to empty if it is null 
    password = password ?? ""; 

    //create the connection 
    using (var connection = new SqlConnection(Configuration.ConnectionString)) 
    { 
     var result = new LoginResult 
     { 
      AttemptsRemaining = 5, 
      Status = LoginStatus.InvalidCredentials 
     }; 
     try 
     { 
      using (var command = new SqlCommand("EXEC ValidateUser @username, @password", connection)) 
      { 
       command.Parameters.AddWithValue("@username", username); 
       command.Parameters.AddWithValue("@password", password); 
       command.CommandType = System.Data.CommandType.Text; 
       connection.Open(); 
       using (var reader = command.ExecuteReader()) 
       { 
        while (reader.Read()) 
        { 
         result.Status = ((LoginStatus)(int)reader["Result"]); 
         result.AttemptsRemaining = (int)reader["AttemptsRemaining"]; 
         break; 
        } 
        reader.Close(); 
       } 
       connection.Close(); 
      } 
      return result; 
     } 
     catch (Exception ex) 
     { 
      if (connection.State != System.Data.ConnectionState.Closed) 
       connection.Close(); 

      Debug.WriteLine("Error on sql query:" + ex.Message); 
      return result; 
     } 
    } 
} 

結果類

public class LoginResult 
{ 
    public LoginStatus Status { get; set; } 

    public int AttemptsRemaining { get; set; } 
} 

public enum LoginStatus : int 
{ 
    Authorized = 0, 
    InvalidCredentials = 1, 
    Suspended = 2 
} 

控制器

[HttpPost] 
public ActionResult Index(string username, string password) 
{ 
    if (string.IsNullOrWhiteSpace(username)) 
    { 
     this.ModelState.AddModelError("", "Invalid Login Credential. No username sent."); 
     return View(); 
    } 
    var manager = new UserManager(); 
    var result = manager.ValidateUserStoredProcedure(username, password); 
    switch (result.Status) 
    { 
     case LoginStatus.Authorized: 
      return RedirectToAction("About", "Home"); 

     case LoginStatus.InvalidCredentials: 
      if (result.AttemptsRemaining < 5) 
       this.ModelState.AddModelError("", "Invalid Login Credentials. Username or password incorrect. Attempts remaining:" + result.AttemptsRemaining); 
      else 
       this.ModelState.AddModelError("", "Invalid Login Credentials. Username or password incorrect."); 
      break; 

     case LoginStatus.Suspended: 
      this.ModelState.AddModelError("", "Account Suspeneded"); 
      break; 
    } 
    return View(); 
} 

您如何進行優化取決於您,但這種授權級別相當薄弱。它還顯示您將密碼存儲爲純文本。但這是另一個話題。

+0

謝謝你ravikumar,我會明天早上測試,讓你知道 – napi15