当天的问候! 我使用表单身份验证,在注册时没关系,但在登录时,它做错了,它只是反过来。 在注册中,假设我输入了密码123,现在它将使用表单身份验证转换该密码,并保存在DB中,现在登录时,如果用户输入123,则会更改,并尝试与数据库中存储的匹配。 在我的情况下,它正在相反,如果密码匹配,它显示,自定义错误消息..如果没有,然后增加锁定帐户的计数器变量
请仔细阅读我的代码,并帮助我......
数据库: -
CREATE TABLE [dbo].[tblUsers](
[ID] [int] IDENTITY(1,1) NOT NULL,
[UserName] [nvarchar](15) NULL,
[Password] [nvarchar](15) NULL,
[Email] [nvarchar](200) NULL,
[RetryAttempts] [int] NULL,
[IsLocked] [bit] NULL,
[LockedDateTime] [datetime] NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE proc [dbo].[sp_RegisterUser]
@UserName nvarchar(15),
@Password nvarchar(15),
@Email nvarchar(200)
As
Begin
Declare @Count int
Declare @ReturnCode int
Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName
if(@Count=1)
Begin
Set @ReturnCode=-1
End
else
Begin
Set @ReturnCode=1
insert into tblUsers(UserName,Password,Email) values(@UserName,@Password,@Email)
End
Select @ReturnCode as ReturnValue
End
CREATE proc [dbo].[SP_AuthenticateUser]
@UserName nvarchar(15),
@Password nvarchar(15)
As
Begin
Declare @Count int
Declare @RetryCount int
Declare @AccountLocked bit
Select @AccountLocked= ISNULL(IsLocked,0) from tblUsers where UserName=@UserName
If(@AccountLocked=1)
Begin
Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
End
Else
Begin
Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName and Password=@Password
If(@Count=1)
Begin
Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
End
Else
Begin
Select @RetryCount=ISNULL(RetryAttempts,0) from tblUsers where UserName=@UserName
Set @RetryCount=@RetryCount+1
If(@RetryCount<=3)
Begin
Update tblUsers set RetryAttempts=@RetryCount where UserName=@UserName
Select 0 as AccountLocked,0 as Authenticate,@RetryCount as RetryAttempts
End
Else
Begin
Update tblUsers set IsLocked=1,LockedDateTime=GETDATE() where UserName=@UserName
Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
End
End
End
End
设计: -
Registration_Page -
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Registration.aspx.cs" Inherits="Registration" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div style="font-family:Arial">
<table style="border: 1px solid black">
<tr>
<td colspan="2">
<b>User Registration</b>
</td>
</tr>
<tr>
<td>
User Name
</td>
<td>
:<asp:TextBox ID="txtUserName" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorusername"
runat="server" ErrorMessage="User Name required" Text="*"
ControlToValidate="txtUserName" ForeColor="Red">
</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
:<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorPassword"
runat="server" ErrorMessage="Password required" Text="*"
ControlToValidate="txtPassword" ForeColor="Red">
</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Confirm Password
</td>
<td>
:<asp:TextBox ID="txtConfirmPassword" TextMode="Password" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorConfirmPassword"
runat="server" ErrorMessage="Confirm Password required" Text="*"
ControlToValidate="txtConfirmPassword" ForeColor="Red"
Display="Dynamic"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="CompareValidatorPassword" runat="server"
ErrorMessage="Password and Confirm Password must match"
ControlToValidate="txtConfirmPassword" ForeColor="Red"
ControlToCompare="txtPassword" Display="Dynamic"
Type="String" Operator="Equal" Text="*">
</asp:CompareValidator>
</td>
</tr>
<tr>
<td>
Email
</td>
<td>
:<asp:TextBox ID="txtEmail" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorEmail"
runat="server" ErrorMessage="Email required" Text="*"
ControlToValidate="txtEmail" ForeColor="Red"
Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="RegularExpressionValidatorEmail"
runat="server" ErrorMessage="Invalid Email" ControlToValidate="txtEmail"
ForeColor="Red" Display="Dynamic" Text="*"
ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
</asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="btnRegister" runat="server" Text="Register"
onclick="btnRegister_Click"/>
</td>
</tr>
<tr>
<td colspan="2">
<asp:Label ID="lblMessage" runat="server" ForeColor="Red">
</asp:Label>
</td>
</tr>
<tr>
<td colspan="2">
<asp:ValidationSummary ID="ValidationSummary1" ForeColor="Red" runat="server" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
登录页面:_
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div style="font-family:Arial">
<table style="border: 1px solid black">
<tr>
<td colspan="2">
<b>Login</b>
</td>
</tr>
<tr>
<td>
User Name
</td>
<td>
:<asp:TextBox ID="txtUserName" runat="server">
</asp:TextBox>
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
:<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
</asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="chk_boxRememberMe" runat="server" Text="Remember Me" />
</td>
<td>
<asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="lblMessage" runat="server" ForeColor="Red"></asp:Label>
</td>
</tr>
</table>
<br />
<a href="Registration/Registration.aspx">Click here to register</a>
if you do not have a user name and password.
</div>
</form>
</body>
</html>
代码背后: -
注册页面: -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;
public partial class Registration : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnRegister_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn=new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter UserName = new SqlParameter("@UserName",txtUserName.Text);
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1");
SqlParameter Password = new SqlParameter("@Password", EncryptPassword);
SqlParameter Email = new SqlParameter("@Email", txtEmail.Text);
cmd.Parameters.Add(UserName);
cmd.Parameters.Add(Password);
cmd.Parameters.Add(Email);
Conn.Open();
int ReturnCode=(int) cmd.ExecuteScalar();
if (ReturnCode==-1)
{
lblMessage.Text = "User Name alredy exists";
}
else
{
Response.Redirect("~/Login.aspx");
}
}
}
}
}
登录页面: -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
//Login_WebConfig();
// Login_DataBase();
if (AuthenticateUser(txtUserName.Text, txtPassword.Text))
{
FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
}
else
{
lblMessage.Text = "Invalid username/password";
}
}
//protected void Login_WebConfig()
//{
// if (FormsAuthentication.Authenticate(txtUserName.Text, txtPassword.Text))
// {
// FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
// }
// else
// {
// lblMessage.Text = "Invalid user name/password";
// }
//}
protected void Login_DataBase()
{
}
private bool AuthenticateUser(string username, string password)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
cmd.CommandType = CommandType.StoredProcedure;
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");
SqlParameter paramUserName = new SqlParameter("@UserName", username);
SqlParameter paramPassword = new SqlParameter("@Password", EncryptPassword);
cmd.Parameters.Add(paramUserName);
cmd.Parameters.Add(paramPassword);
Conn.Open();
int ReturnCode = (int)cmd.ExecuteScalar();
return ReturnCode == 1;
}
}
}
网络配置:
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="Welcome.aspx" timeout="2" protection="All">
<!--<credentials passwordFormat="Clear">
<user name="rkbisht" password="1234"/>
</credentials>-->
</forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
<appSettings>
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
</appSettings>
<connectionStrings>
<add name="con" connectionString="Data Source=.;Initial Catalog=Security_Learning;Integrated Security=true"/>
</connectionStrings>
</configuration>
答案 0 :(得分:0)
基本上,您没有使用正确的工具来完成工作。
您并未真正使用FormsAuthentication
而且您也没有将哈希保存在配置文件中,因此FormsAuthentication.HashPasswordForStoringInConfig
不是您应该使用的。
值得花些时间来做这件事。这是一个起点:
https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing
注意,你应该使用哈希和盐,盐应该是每个用户唯一的。
我个人使用Microsoft.AspNetCore.Cryptography.KeyDerivation nuget包,其实现类似于以下内容:
助手类
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Resources;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
public static class SecurityHelper
{
public static int DefaultIterations = 10000
//KeyDerivation.Pbkdf2
/// <summary>
/// Generates a random salt
/// </summary>
/// <returns>A byte array containing a random salt</returns>
public static byte[] GetRandomSalt()
{
byte[] saltBytes = new byte[32];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(saltBytes);
return saltBytes;
}
public static string GeneratePasswordHash(string plainPassword, int iterations, out string generatedRandomSalt)
{
generatedRandomSalt = Convert.ToBase64String(GetRandomSalt());
return Convert.ToBase64String(ComputeHash(plainPassword, generatedRandomSalt, iterations));
}
public static string GetPasswordHash(string plainPassword, string existingSalt, int iterations)
{
return Convert.ToBase64String(ComputeHash(plainPassword, existingSalt, iterations));
}
private static byte[] ComputeHash(string plainText, string salt, int iterations)
{
return KeyDerivation.Pbkdf2(
password: plainText,
salt: Convert.FromBase64String(salt),
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: iterations,
numBytesRequested: 32);
}
}
您的工作流程现已更改:
粗略
//Registration
using (SqlConnection Conn=new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter UserName = new SqlParameter("@UserName",txtUserName.Text);
string Salt = string.Empty;
string Password = SecurityHelper.GeneratePasswordHash(txtPassword.Text, SecurityHelper.DefaultIterations, out salt);
;
SqlParameter Password = new SqlParameter("@Password", Password);
SqlParameter Email = new SqlParameter("@Email", txtEmail.Text);
SqlParameter Salt = new SqlParameter("@Salt", Salt);
cmd.Parameters.Add(UserName);
cmd.Parameters.Add(Password);
cmd.Parameters.Add(Email);
Conn.Open();
int ReturnCode=(int) cmd.ExecuteScalar();
if (ReturnCode==-1)
{
lblMessage.Text = "User Name alredy exists";
}
else
{
Response.Redirect("~/Login.aspx");
}
}
//Log In
private bool AuthenticateUser(string username, string password)
{
//Get the following from your database based on username
string savedHash = //fromDB;
string savedSalt = //fromDb;
return (SecurityHelper.GetPasswordHash(password, savedSalt, SecurityHelper.DefaultIterations) == tempUser.Password)
}
我有点简化了。我还在数据库中保存针对用户的迭代,以防我们需要增加默认迭代。
我最后的一点点,所以读一些关于为什么“腌制”是一件好事。
答案 1 :(得分:0)
您的身份验证存储过程(SP_AuthenticateUser
)会返回3列,但您使用ExecuteScalar
进行调用。您需要获取数据集并检查第二列。
private bool AuthenticateUser(string username, string password)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
cmd.CommandType = CommandType.StoredProcedure;
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");
SqlParameter paramUserName = new SqlParameter("@UserName", username);
SqlParameter paramPassword = new SqlParameter("@Password", EncryptPassword);
cmd.Parameters.Add(paramUserName);
cmd.Parameters.Add(paramPassword);
Conn.Open();
var reader = cmd.ExecuteReader();
reader.Read();
return reader["Authenticate"] as bool;
}
}
此外,请确保在成功验证后重置重试计数器。
Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName and Password=@Password
If(@Count=1)
Begin
Update tblUsers set RetryAttempts = 0 where UserName = @UserName
Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
End
您的代码也存在其他一些问题,但这两个问题可能会导致您的问题中出现的行为。
Here is a better way to hash your password
除非您设置表单身份验证Cookie,否则用户必须继续登录。 Click here for ideas on how
您可能不需要web.config中的凭据。如果您打算使用FormsAuthentication.Authenticate,则只需将它们放在那里。您似乎正在使用数据库。