我们通过用用户的凭据调用Web服务并返回包含用户ID的WCF结构,即" logonticket",从而覆盖了MVC3应用程序中的基本身份验证。此logonticket用于"为对Web服务的每个调用进行身份验证用户。
现在,我们通过在web.config中替换DefaultProvider来覆盖。我们在这个覆盖的提供商中所做的就是覆盖ValidateUser()函数。那就是我们以其凭据调用Web服务并返回的地方" logonticket"。
这是来自我们的accountController的logon()函数,本质上是模板中的基本代码:
public ActionResult LogOn(LogOnModel model)
{
string ReturnUrl = "";
if (HttpContext.Request.UrlReferrer.Query.Length > 11)
{
ReturnUrl = Uri.UnescapeDataString(HttpContext.Request.UrlReferrer.Query.Substring(11));
}
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
ViewBag.MainWebsite = MainWebsite;
return View(model);
}
这是我们新默认提供商的覆盖validateUser()函数:
public override bool ValidateUser(string username, string password)
{
MyServiceClient mps = new MyServiceClient();
string sha1password = HashCode(password);
LogonInfo logonInfo = mps.GetLogonTicket(username, sha1password);
if (logonInfo.LogonTicket != "" && logonInfo.LogonTicket != "0")
{
// Authenticated so set session variables
HttpContext.Current.Session["LogonTicket"] = logonInfo.LogonTicket;
HttpContext.Current.Session["ParticipantID"] = logonInfo.ParticipantID;
return true;
}
else
{
return false;
}
}
我不太确定如何结合两者的使用,所以我的问题是:
- 如何实现OpenID和Facebook登录并保留我当前的身份验证方法?
- 如何使用当前用户数据库值"映射" OpenID用户?我们必须知道,以便我们可以检索他们的信息。 我知道我们可以检索他们的电子邮件地址,但是如果他们的OpenID电子邮件与他们在我们网站上的记录中使用的电子邮件不同,该怎么办?
- 是否有任何示例有关如何执行此操作?
感谢您查看我的问题。
我完成了一个需要多个日志可能性的项目(自定义帐户,Google和Facebook)
最后,您使用ASP.NET的身份验证完全取决于您的配置。(在您的情况下,这是formauthentication)这意味着 FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
基本确定对用户的所有内容以及在何处设置的所有内容。
您现在使用MementHippRovider来处理您自己的自定义帐户的基本实现基本相同。您现在只需要扩展即可促进OpenID。您必须为每种登录类型的各种操作扩展Controller
(现在您有ActionResult LogOn()
可以添加到例如:ActionResult LogOnOpenId()
)。在该方法中,您可以基本调用相同的代码,而不是Membership.ValidateUser(model.UserName, model.Password)
您调用OpenID服务。
我在下面提供了使用dotnetopenauth的Google实施示例。该服务方法使用formsService.SignIn(userId.Value.ToString(), false);
基本调用FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
(我们在SecurityPrincipal方面只做一些自定义行为,但这不会影响您的身份验证过程)。您还可以看到,当我们收到新用户时,我们会创建一个新帐户。为了解决您的问题第2部分,我们实施了一个配置文件,如果您可以提供另一个登录名,则可以合并。这使我们的用户可以保持其帐户合并并使用他们喜欢的任何登录方法。
有关多个签名的示例,我将提到Tomas的答案,Tomas将Stackexchange称为一个很好的例子。另外,我建议您安装MVC4和VS2012,然后进行文件>新项目。MVC的最新默认模板包括OpenID实现以及自定义登录!
示例Google OpenID实现:
控制器方法:
public virtual ActionResult LoginGoogle(string returnUrl, string runAction)
{
using (var openId = new OpenIdRelyingParty())
{
IAuthenticationResponse response = openId.GetResponse();
// If we have no response, start
if (response == null)
{
// Create a request and redirect the user
IAuthenticationRequest req = openId.CreateRequest(WellKnownProviders.Google);
var fetch = new FetchRequest();
fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
fetch.Attributes.AddRequired(WellKnownAttributes.Preferences.Language);
req.AddExtension(fetch);
req.RedirectToProvider();
return null;
}
_service.ConnectViaGoogle(response, TempData);
}
服务方法:
public void ConnectViaGoogle(IAuthenticationResponse response, TempDataDictionary tempData)
{
// We got a response - check it's valid and that it's me
if (response.Status == AuthenticationStatus.Authenticated)
{
var claim = response.GetExtension<FetchResponse>();
Identifier googleUserId = response.ClaimedIdentifier;
string email = string.Empty;
string firstName = string.Empty;
string lastName = string.Empty;
string language = string.Empty;
if (claim != null)
{
email = claim.GetAttributeValue(WellKnownAttributes.Contact.Email);
firstName = claim.GetAttributeValue(WellKnownAttributes.Name.First);
lastName = claim.GetAttributeValue(WellKnownAttributes.Name.Last);
language = claim.GetAttributeValue(WellKnownAttributes.Preferences.Language);
}
//Search User with google UserId
int? userId = _userBL.GetUserIdByGoogleSingleSignOnId(googleUserId);
//if not exists -> Create
if (!userId.HasValue)
{
_userBL.CreateGoogleUser(
googleUserId,
firstName,
lastName,
email,
language,
DBConstants.UserStatus.DefaultStatusId,
out userId);
}
if (userId.HasValue)
{
_userBL.UpdateLastLogon(userId.Value);
var formsService = new FormsAuthenticationService();
formsService.SignIn(userId.Value.ToString(), false);
AfterLoginActions(tempData);
}
}
}
有任何问题或评论吗?我很乐意听到他们的声音。
- 应该完全有可能拥有多种身份验证方法。IIS/ASP.NET所关心的只是formauthentication cookie。因此,您将为您的标准用户名/密码auth提供一组操作,而另一组则为OpenID。这至少是我在一个项目上所做的。
- 您甚至不能相信OpenID提供商可以为您提供电子邮件地址!解决此问题的一个常见解决方案是允许用户在登录后将多个OpenID标识符(URI)附加到他的帐户上。这是例如stackoverflow如何工作。如果这是用户第一次访问系统,则可以自动创建一个新帐户,或者通过注册过程迫使用户。
当我在提到的系统中添加OpenID支持时,它具有用于存储用户名和密码(用户表)的现有表。我添加了一个与用户表有多一到一段关系的新表格,并用它来存储URI。 - 如上所述,stackoverflow它是一个很好的起点,http://www.dotnetopenauth.net/project中也有很多很好的例子。据我所知,SO的来源不是公开,他们正在使用dotnetopenauth项目。
这可能是抽象的,但是该库是开源果园CMS的开放式(除其他方面):http://orchardopenauth.codeplex.com/
我希望这会有所帮助,但是如果您有任何疑问,请通过更多详细信息扩展您的问题。