C# SQL Server验证返回错误的输出

C# SQL Server验证返回错误的输出,c#,asp.net,sql-server,C#,Asp.net,Sql Server,我正在使用SQL server在本地服务器上进行登录页面验证。我创建了一个登录页面和注册页面,我的注册页面工作正常,但登录页面一直显示用户未激活的错误 这是我登录页面的代码 public partial class Login : System.Web.UI.Page { protected void Validate_User(object sender, EventArgs e) { int userId = 0

我正在使用SQL server在本地服务器上进行登录页面验证。我创建了一个登录页面和注册页面,我的注册页面工作正常,但登录页面一直显示用户未激活的错误

这是我登录页面的代码

public partial class Login : System.Web.UI.Page
{
            protected void Validate_User(object sender, EventArgs e)
            {
                int userId = 0;
                string constr = `ConfigurationManager.ConnectionStrings["constr"].ConnectionString;`

                using (SqlConnection con = new SqlConnection(constr))
                {
                    using (SqlCommand cmd = new SqlCommand("Validate_User"))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.Parameters.AddWithValue("@Username", Login1.UserName);
                        cmd.Parameters.AddWithValue("@Password", Login1.Password);
                        cmd.Connection = con;
                        con.Open();
                        userId = Convert.ToInt32(cmd.ExecuteScalar());
                        con.Close();
                    }

                    switch (userId)
                    {
                        case -1:
                            Login1.FailureText = "Username and/or password is incorrect.";
                            break;
                        case -2:
                            Login1.FailureText = "Account has not been activated.";
                            break;
                        default:

                            FormsAuthentication.RedirectFromLoginPage(Login1.UserName, Login1.RememberMeSet);
                            break;
                    }

                }
            }
}
下面是验证用户的过程

CREATE PROCEDURE [dbo].[Validate_User]
    @Username NCHAR(50),
    @Password VARCHAR(50)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @UserId INT, @LastLoginDate DATETIME

    SELECT @UserId = UserId, @LastLoginDate = LastLoginDate
    FROM NervSuiteUsers 
    WHERE Username = @UserName AND [Password] = @Password

    IF @UserId IS NOT NULL
    BEGIN
        IF NOT EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName)
        BEGIN
            UPDATE NervSuiteUsers
            SET LastLoginDate = GETDATE()
            WHERE UserId = @UserId

            SELECT @UserName [UserName] -- User Valid
        END
        ELSE
        BEGIN
            SELECT -2 -- User not activated.
        END
    END
    ELSE
    BEGIN
        SELECT -1 -- User invalid.
    END
END

问题是,即使数据库中有一个用户,我仍然得到未验证的帐户

您的SP对我做出了矛盾的陈述。只有当用户名/密码匹配时,下面的查询才会给出结果

SELECT @UserId = UserId, @LastLoginDate = LastLoginDate
FROM NervSuiteUsers 
WHERE Username = @UserName AND [Password] = @Password
那么下面的这个查询就没有意义了

IF @UserId IS NOT NULL // will be true when both username/password matches
BEGIN
    IF NOT EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName) // Why this???? This will not be TRUE
    BEGIN
        UPDATE NervSuiteUsers
        SET LastLoginDate = GETDATE()
        WHERE UserId = @UserId
因此,您的else块将得到评估,您将得到发布的结果

    ELSE
    BEGIN
        SELECT -2 -- User not activated.
    END

你的SP对我的陈述自相矛盾。只有当用户名/密码匹配时,下面的查询才会给出结果

SELECT @UserId = UserId, @LastLoginDate = LastLoginDate
FROM NervSuiteUsers 
WHERE Username = @UserName AND [Password] = @Password
那么下面的这个查询就没有意义了

IF @UserId IS NOT NULL // will be true when both username/password matches
BEGIN
    IF NOT EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName) // Why this???? This will not be TRUE
    BEGIN
        UPDATE NervSuiteUsers
        SET LastLoginDate = GETDATE()
        WHERE UserId = @UserId
因此,您的else块将得到评估,您将得到发布的结果

    ELSE
    BEGIN
        SELECT -2 -- User not activated.
    END

除了您在关于实现问题的评论中得到的所有反馈之外,您还对以下几行查询有意见

IF NOT EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName)
        BEGIN
            UPDATE NervSuiteUsers
            SET LastLoginDate = GETDATE()
            WHERE UserId = @UserId

            SELECT @UserName [UserName] -- User Valid
        END
        ELSE
        BEGIN
            SELECT -2 -- User not activated.
        END
它不应该不存在。它应该是存在的,因为@UserId NOT NULL意味着它存在于表中,请按如下方式更改查询

IF EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName)
        BEGIN
            UPDATE NervSuiteUsers
            SET LastLoginDate = GETDATE()
            WHERE UserId = @UserId

            SELECT @UserName [UserName] -- User Valid
        END
        ELSE
        BEGIN
            SELECT -2 -- User not activated.
        END

除了您在关于实现问题的评论中得到的所有反馈之外,您还对以下几行查询有意见

IF NOT EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName)
        BEGIN
            UPDATE NervSuiteUsers
            SET LastLoginDate = GETDATE()
            WHERE UserId = @UserId

            SELECT @UserName [UserName] -- User Valid
        END
        ELSE
        BEGIN
            SELECT -2 -- User not activated.
        END
它不应该不存在。它应该是存在的,因为@UserId NOT NULL意味着它存在于表中,请按如下方式更改查询

IF EXISTS(SELECT UserId FROM NervSuiteUsers WHERE Username = @UserName)
        BEGIN
            UPDATE NervSuiteUsers
            SET LastLoginDate = GETDATE()
            WHERE UserId = @UserId

            SELECT @UserName [UserName] -- User Valid
        END
        ELSE
        BEGIN
            SELECT -2 -- User not activated.
        END

除了已经讨论过的SP中的小故障外,.NET代码中还存在与结果是整数失败还是字符串成功相关的问题。解决这个问题的一个实用方法是始终返回相同的类型。由于用户传入用户名,因此再次传出用户名不一定有什么意义,除非您的目的是自动更正不区分大小写的字符串,但一个简单的修复方法是在成功案例中只选择1或其他哨兵值,而不是选择@username

但是,在现有代码中也可以解决相同的问题,只需测试以下值:

object sqlResult = cmd.ExecuteScalar();
switch (sqlResult)
{
    case int i when i == -1:
        // TODO ...
        break;
    case int i when i == -2:
        // TODO ...
        break;
    case string s:
        // success, and the value was s
        // TODO...
        break;
    default:
        // I HAVE NO CLUE
        throw new SomeSensibleException(...);
}
注意:这使用了新的C语言语法功能,但如果使用低级C,同样的基本方法也可以通过以下方式手动完成:

if (sqlResult is int)
{
    switch ((int)sqlResult)
    {
       // ...
    }
}
else if (sqlResult is string)
{
    string s = (string)sqlResult;
    // ...
}

除了已经讨论过的SP中的小故障外,.NET代码中还存在与结果是整数失败还是字符串成功相关的问题。解决这个问题的一个实用方法是始终返回相同的类型。由于用户传入用户名,因此再次传出用户名不一定有什么意义,除非您的目的是自动更正不区分大小写的字符串,但一个简单的修复方法是在成功案例中只选择1或其他哨兵值,而不是选择@username

但是,在现有代码中也可以解决相同的问题,只需测试以下值:

object sqlResult = cmd.ExecuteScalar();
switch (sqlResult)
{
    case int i when i == -1:
        // TODO ...
        break;
    case int i when i == -2:
        // TODO ...
        break;
    case string s:
        // success, and the value was s
        // TODO...
        break;
    default:
        // I HAVE NO CLUE
        throw new SomeSensibleException(...);
}
注意:这使用了新的C语言语法功能,但如果使用低级C,同样的基本方法也可以通过以下方式手动完成:

if (sqlResult is int)
{
    switch ((int)sqlResult)
    {
       // ...
    }
}
else if (sqlResult is string)
{
    string s = (string)sqlResult;
    // ...
}

我个人不使用SELECT,而是在这里使用输出参数。这说明了如何使用它们。真正严重的问题是,您似乎正在以纯文本形式存储和传输密码。在你认真阅读散列和盐类之前,停止这一点。你为什么不使用ASP.NET自己的授权机制呢?存储密码,即使是加密的,也是一个非常糟糕的主意。这一行:[密码]=@密码应该出现在每个面试问题中。认真地仍然有人这样做,他们不仅在他们的系统中制造漏洞,而且还真的将私人信息转储给第三方……如果我们忽略已经讨论过的纯文本密码问题,它看起来应该可以正常工作。所以要做的第一件事是隔离尝试SP,例如通过SSM。如果SP不工作:请修复该问题。如果SP在SSMS中工作正常,那么您需要查看ExecuteScalar之后的用户ID。在这些情况下是什么?作为旁注,根据逻辑流在integer和nvarchar的位置返回不同的类型是非常有问题的——我个人会避免这样做。我希望convert抛出异常,因为它在正常情况下不是整数。我个人不使用SELECT,而是在这里使用输出参数。这说明了如何使用它们。真正严重的问题是,您似乎正在以纯文本形式存储和传输密码。在你认真阅读散列和盐类之前,停止这一点。你为什么不使用ASP.NET自己的授权机制呢?存储密码,即使是加密的,也是一个非常糟糕的主意。这一行:[密码]=@密码应该出现在每个面试问题中。认真地仍然有人这样做,他们不仅在他们的系统中制造了漏洞,而且还真的将私人信息转储给第三方……如果我们忽略了
纯文本密码问题已经讨论过了,看起来应该可以正常工作。所以要做的第一件事是隔离尝试SP,例如通过SSM。如果SP不工作:请修复该问题。如果SP在SSMS中工作正常,那么您需要查看ExecuteScalar之后的用户ID。在这些情况下是什么?作为旁注,根据逻辑流在integer和nvarchar的位置返回不同的类型是非常有问题的——我个人会避免这样做。我希望转换会抛出一个异常,因为它在正常情况下不是整数。这是可行的,我已经这样做了,但仍然得到了相同的结果。显然,在运行之前我没有更新脚本和过程,因此我再次出现了错误。对不起,我无法理解您。你能解释一下更改后出现了什么问题吗?没有问题,我的意思是我更改了代码以删除先前语句中的NOT,但仍然有相同的先前错误,因为我没有更新脚本。现在很好用了。这很有效,我已经做了,但还是得到了同样的结果。显然,在运行之前我没有更新脚本和过程,因此我再次出现了错误。对不起,我无法理解您。你能解释一下更改后出现了什么问题吗?没有问题,我的意思是我更改了代码以删除先前语句中的NOT,但仍然有相同的先前错误,因为我没有更新脚本。现在很好用。