我正在开发一个使用 Asp.Net 的成员资格和角色功能的 Asp.Net 4.0 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 框架的好处,因为“访问者”很可能有几个链接发送给他们,随着时间的推移,不同的文档和文档版本会被添加和更改。
谁能想到更好的方法?到目前为止,我已经在这里和这里查看了大多数相关条目,但它们似乎都有些不完整。
编辑
使用从此处接受的答案中收集的信息,我似乎至少部分解决了这个问题
本质上,问题是我的 web.config 成员资格部分需要被告知要使用哪种散列算法。目前,我不知道默认的是什么,如果有的话,但是添加
<membership hashAlgorithmType="SHA1">
到 web.config 至少允许我登录添加上述行后创建的用户。下一步是让我了解为什么我无法让其他用户登录。
但是,我仍然收到 Joe 建议的 ThreadAbortException,我现在正忙于解决这个问题。