以编程方式登录到asp.net成员资格和角色?

6
我正在开发一个使用Asp.Net的Membership和Roles功能的Web应用程序。
在应用程序中,有三个角色可以访问登录页面,而另一个角色则无法访问。
它应该按照以下方式工作:
后端用户(属于三个特权角色之一)创建一个用户。在代码中,这是通过编程方式完成的,而不是使用注册用户页面。创建用户时,将其添加到非特权角色中,为了清晰起见,称为“访客”角色。
然后,后端用户为新用户创建一个链接,形式为https://www.example.com?link=cc82ae24-df47-4dbf-9440-1a6923945cf2
当访问链接时,应用程序将定位与查询字符串相关联的用户,获取用户名和密码(适当地进行哈希和盐处理),并登录用户。
这是我不知道该怎么办了的地方。到目前为止,用户创建正常运行,基于查询字符串值的数据库查询正在发挥作用并返回相关信息,所有似乎都很顺利,除了实际的登录。似乎没有清晰的编程登录用户的方法,而不需要让用户自己登录,但我已明确被告知要避免这样做。
这是我的代码,“pers”对象是从数据库填充的类,当他们着陆链接的默认页面时:
protected void LogUserIn(string p)
{
    SqlConnection conn = UtilityMethods.GetConnection();
    Guid par = Guid.Parse(p);
    BioProspect pers= new BioProspect(conn);
    pers.FillDetailsFromDb(par);

    testlable.Text = pers.ToString();
    Response.Cookies.Remove(FormsAuthentication.FormsCookieName);

    try
    {
        if (Membership.ValidateUser(pers.Email, pers.Pword))
        {

            FormsAuthentication.SetAuthCookie(pers.Email, true);

            Response.Redirect(Request.Url.Scheme + "://" + Request.Url.Host + "/About.aspx");
            testlable.Text = "Logged in!";
        }
        else
        {
            throw new Exception("Something went wrong");
        }
    }
    catch (Exception ex)
    {
        StringBuilder sb = new StringBuilder();
        foreach (DictionaryEntry d in ex.Data)
        {
            sb.Append(d.Key.ToString());
            sb.Append(": ");
            sb.Append(d.Value.ToString());
            sb.Append("\r\n");
        }

        AMessage(sb.ToString());
    }
}

现在,我已经检查了用户名和密码与数据库表本身的值,并且一切都是正确的。我理解aspnet表中存储的密码已被加盐和哈希,因此我正在检查我创建的临时表中的明文值。这是正确的。此外,在上面的代码中,FormsAuthentication.SetAuthCookie方法要求提供用户名和密码-在这种情况下,用户名是电子邮件地址。调试期间检查此信息也是正确的。
我应该指出,我们发送的链接基本上是一次性链接。每当针对特定用户进行更改时,链接参数的值都会更改,旧链接将变得完全无用。他们将被重定向到的页面将包含直接与该特定用户相关的文件,而不是其他任何人。
然而,我们仍然需要Asp.Net Membership、Profiles和Roles框架的好处,因为“访客”可能会收到几个链接,随着时间的推移,不同的文档和文档版本会被添加和更改。

有没有更好的方法?我至今已经查看了大多数相关条目herehere,但它们似乎都有些不完整。

编辑

我似乎已经部分解决了这个问题,使用从被接受的答案中获得的信息here

实际上,问题在于我的web.config成员身份验证部分需要告诉使用哪个哈希算法。目前,我不知道默认的哈希算法是什么,如果有的话,但是添加以下内容:

<membership hashAlgorithmType="SHA1">

将web.config文件进行更改,至少使我能够记录在上述行添加后创建的用户登录。下一步是让我了解为什么无法让其他用户登录。
然而,正如Joe所建议的那样,我仍然会遇到ThreadAbortException异常,并且现在我正在忙于解决它。
2个回答

10

我不确定我完全理解你的问题,但调用 FormsAuthentication.SetAuthCookie 本质上会在程序中登录用户。

此外,在上面的代码中,FormsAuthentication.SetAuthCookie方法要求提供用户名和密码。

不,SetAuthCookie需要一个用户名,但不需要密码。

在你的样本代码中,对 Response.Redirect 的调用会引发 ThreadAbortException,因此你的 catch 块将执行。也许这让你感到困惑。

回应评论:

基本上,我遇到的问题是似乎没有将用户登录。FormsAuthenticate方法返回false。

在上面的代码中没有 FormsAuthenticate 方法。

话虽如此,我不明白为什么你在这种情况下要认证用户(Membership.ValidateUser)。我认为你只需找到与查询字符串相关联的用户名,然后简单地调用 FormsAuthentication.SetAuthCookie 来登录他即可。


嗨Joe,感谢你的回答。你是对的,它没有要求密码,在代码中,我没有传递密码。再次出现ThreadAbortException异常,但我必须承认我不明白为什么会出现这种情况。我过去曾使用该方法在页面之间进行重定向,似乎可以正常工作。话虽如此,try..catch块没有捕获到该特定异常。如果我省略else块,则try..catch不会捕获任何内容。 - inksmithy
我遇到的问题基本上是用户似乎无法登录。FormsAuthenticate 方法返回 false。 - inksmithy
1
我不想验证一个未激活的用户,这种情况下你应该调用Membership.GetUser并检查用户是否处于激活状态。但我不明白为什么你要进行身份验证,因为这需要你访问未加密的密码。如果Membership.ValidateUser返回false,并且你的用户名有效,则说明你的密码不正确。 - Joe
我的基本计划是确保用户有效,然后使用GetUser检查状态,一旦所有细节都处理完毕,就对用户进行身份验证。我已经编辑了问题,以显示我现在似乎已经按照预期进行了身份验证。但是,我仍然对ThreadAbortException感到困惑 - a)您如何知道它会发生,b)请问我该如何停止它?我目前正在研究它。 - inksmithy
2
@inkysmithy,你正在使用的Response.Redirect重载将通过抛出ThreadAbortException立即终止当前请求。这种行为意味着在Response.Redirect之后页面生命周期中的代码不会被执行。如果你不想要这种行为,可以使用带有endResponse参数的Response.Redirect重载,你可以将其设置为false - Joe
显示剩余3条评论

1
我知道存储在aspnet表中的密码已经被加盐和哈希,所以我正在检查我创建的临时表中保存的明文值。这是正确的。此外,在上面的代码中,FormsAuthentication.SetAuthCookie方法要求提供用户名和密码 - 在这种情况下,用户名是电子邮件地址。在调试期间检查时,这些信息也是正确的。
请不要以明文形式存储密码或任何密码。
基本上,我遇到的问题是用户似乎无法登录。FormsAuthenticate方法返回false。
您确定这不仅仅是一个cookie问题吗?
看起来您应该能够提供存储的密码哈希和用户名并登录到该用户帐户。只需覆盖哈希“密码”的方法,而将受保护的密码转发到身份验证系统即可。

你好,感谢您的回复。目前为了调试,我正在使用临时表来存储明文密码。生产应用程序将确实有盐值和哈希密码。针对您的问题,我并不确定这是否只是一个cookie问题。目前,我正在尝试每种可能的方法来解决它 - 如果我可以让登录工作,那么我就会开始找出为什么它起作用以及其他方法为什么没有起作用。但目前,Membership.ValidateUser(uname,pwd)似乎什么也没发生。 - inksmithy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接