asp.net-mvc – 如何在ASP.NET MVC4中使用具有唯一标识符URL的OpenID提供程序
|
在ASP.NET MVC4中实现的新SimpleMembershipProvider允许对两个流行的OpenID提供商(Google和Yahoo)和三个OAuth提供商(Microsoft,Facebook,Twitter)进行简单的内置支持. 在 例如,所有用户的Google OpenID服务网址均为https://www.google.com/accounts/o8/id. 这适用于MVC4中的SimpleMembershipProvider,在您的MVC应用程序启动时,身份提供者的URL需要被知道,不变和注册. 问题是,其他OpenID提供者通常使用用户唯一的OpenID标识符作为访问身份服务的URL. 例如,AOL和WordPress分别使用https://openid.aol.com/{username}和https:// {username} .wordpress.com. 如果您将SimpleMembershipProvider替换为您自己的ExtendedMembershipProvider实现,那么您可以滚动自己的提供程序实现,但是它不会与MVC4帐户控制器开箱即用. 当提供者使用URL中的用户名唯一标识符时,如何使用SimpleMembershipProvider实现新的OpenID依赖方? 解决方法我开发了以下解决方案,适用于我,我正在分享,以帮助他人,但我真的很想看看是否有一个更直接的方法或“最佳实践”,我错过了.基本上,您需要实现一个OpenIdClient,它使用一个包含关键字__username__的URL的ProviderIdentifier进行初始化. 在运行时,提供者名称和用户名将传递给帐户控制器,在该控制器中,提供者客户端按名称进行选择,用户名替换为__username__关键字,然后认证请求将发送给提供商. OpenID客户端 由Microsoft提供的DotNetOpenAuth OpenID提供程序类继承了基类 要在运行时创建自定义URL,我们将接受OpenID用户名作为URI片段,并将URL中的所有__username__实例替换为用户提交的用户名.提供商需要在应用程序启动期间注册URL,因此,当用户名已知时,我们不能在运行时注册提供程序URL. 我们将使用OpenID Selector将表单提交给我们的Account控制器的ExternalLogin操作,其提供者表单值设置为格式提供者{username}中的提供者名称和用户名. OpenId Selector具有内置的逻辑,用于将{username}的所有实例替换为向用户呈现的文本框的输入.在服务器端,我们将从用户名中分离提供程序名称,按照应用程序启动时注册的名称查找提供者,并将GenericOpenIdClient.UserName属性设置为用户名提交的用户名. 当创建认证请求以发送到OpenID提供程序时,我们将检查GenericOpenIdClient.UserName属性,如果设置,我们将在发送请求之前使用用户名重新创建提供程序URL.为了做到这一点,我们需要重写RequestAuthentication()方法来创建使用我们的自定义URL的身份验证请求. __username__而不是{username},因为{和}不是主机名的有效字符,因此当我们需要将其注册为通用提供者标识符时,创建包含它们的URL变得有问题. /GenericOpenIdClient.cs namespace DotNetOpenAuth.AspNet.Clients
{
using System;
using System.Collections.Generic;
using System.Web;
using System.Xml.Linq;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.RelyingParty;
public class GenericOpenIdClient : OpenIdClient
{
#region Constants and Fields
/// <summary>
/// The openid relying party.
/// </summary>
/// <remarks>
/// Pass null as applicationStore to specify dumb mode. Create a protected field to use internally; we can't access the private base class field.
/// </remarks>
protected static readonly OpenIdRelyingParty RelyingParty = new OpenIdRelyingParty(applicationStore: null);
/// <summary>
/// The provider identifier.
/// </summary>
/// <remarks>
/// Create a protected field to use internally; we can't access the private base class field.
/// </remarks>
protected readonly Identifier providerIdentifier;
#endregion
#region Constructors and Destructors
public GenericOpenIdClient(string providerName,Identifier providerIdentifier)
: base(providerName,providerIdentifier)
{
this.providerIdentifier = providerIdentifier; // initialize our internal field as well
}
#endregion
#region Public Properties
public String UserName { get; set; }
#endregion
#region Protected Properties
/// <summary>
/// The provider Identifier with the "__username__" keyword replaced with the value of the UserName property.
/// </summary>
protected Identifier ProviderIdentifier
{
get
{
var customIdentifier = String.IsNullOrWhiteSpace(this.UserName) ?
this.providerIdentifier :
Identifier.Parse(HttpUtility.UrlDecode(this.providerIdentifier).Replace("__username__",this.UserName));
return customIdentifier;
}
}
#endregion
#region Methods
/// <summary>
/// Gets the extra data obtained from the response message when authentication is successful.
/// </summary>
/// <param name="response">
/// The response message.
/// </param>
/// <returns>A dictionary of profile data; or null if no data is available.</returns>
protected override Dictionary<string,string> GetExtraData(IAuthenticationResponse response)
{
FetchResponse fetchResponse = response.GetExtension<FetchResponse>();
if (fetchResponse != null)
{
var extraData = new Dictionary<string,string>();
extraData.AddItemIfNotEmpty("email",fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email));
extraData.AddItemIfNotEmpty("country",fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.Country));
extraData.AddItemIfNotEmpty("firstName",fetchResponse.GetAttributeValue(WellKnownAttributes.Name.First));
extraData.AddItemIfNotEmpty("lastName",fetchResponse.GetAttributeValue(WellKnownAttributes.Name.Last));
return extraData;
}
return null;
}
public override void RequestAuthentication(HttpContextBase context,Uri returnUrl)
{
var realm = new Realm(returnUrl.GetComponents(UriComponents.SchemeAndServer,UriFormat.Unescaped));
IAuthenticationRequest request = RelyingParty.CreateRequest(ProviderIdentifier,realm,returnUrl);
// give subclasses a chance to modify request message,e.g. add extension attributes,etc.
this.OnBeforeSendingAuthenticationRequest(request);
request.RedirectToProvider();
}
/// <summary>
/// Called just before the authentication request is sent to service provider.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
protected override void OnBeforeSendingAuthenticationRequest(IAuthenticationRequest request)
{
// Attribute Exchange extensions
var fetchRequest = new FetchRequest();
fetchRequest.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
fetchRequest.Attributes.AddOptional(WellKnownAttributes.Contact.HomeAddress.Country);
fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.First);
fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.Last);
request.AddExtension(fetchRequest);
}
#endregion
}
/// <summary>
/// The dictionary extensions.
/// </summary>
internal static class DictionaryExtensions
{
/// <summary>
/// Adds the value from an XDocument with the specified element name if it's not empty.
/// </summary>
/// <param name="dictionary">
/// The dictionary.
/// </param>
/// <param name="document">
/// The document.
/// </param>
/// <param name="elementName">
/// Name of the element.
/// </param>
public static void AddDataIfNotEmpty(
this Dictionary<string,string> dictionary,XDocument document,string elementName)
{
var element = document.Root.Element(elementName);
if (element != null)
{
dictionary.AddItemIfNotEmpty(elementName,element.Value);
}
}
/// <summary>
/// Adds a key/value pair to the specified dictionary if the value is not null or empty.
/// </summary>
/// <param name="dictionary">
/// The dictionary.
/// </param>
/// <param name="key">
/// The key.
/// </param>
/// <param name="value">
/// The value.
/// </param>
public static void AddItemIfNotEmpty(this IDictionary<string,string key,string value)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
if (!string.IsNullOrEmpty(value))
{
dictionary[key] = value;
}
}
}
}
(编辑:哈尔滨站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc – 从Api控制器内生成绝对的url to action
- ASP.NET web.config文件是否失控?
- 如何在ASP.NET中的GridView中定义CellPadding
- 用AJAX实现的无刷新的分页实现代码(asp.net)
- ASP.NET中的超链接控件和链接控件有什么区别?
- asp.net – 从启用AJAX的WCF服务返回错误详细信息
- 如何单元测试我的asp.net-mvc控制器的OnActionExecuting方法
- asp.net-mvc – MVC 5:Asp.net身份:如何建模UserRole
- 所有我使用IO的动作都是异步的?
- asp.net-mvc – 为什么MVC4捆绑捆绑Knockout.js?
- VS 2013 RC中缺少ASP.NET Web窗体脚手架功能
- asp.net-mvc – 如何在ASP.NET MVC中生成弹出页面
- asp.net-mvc-5 – 我需要在MVC Razor中编码属性值
- asp.net-mvc – ASP.NET MVC Beta 1:DefaultMod
- asp.net中的GridView分页问题
- ASP.Net核心 – 获取帖子表格的所有数据
- ASP.net WebAPI跨域调用问题的解决方法
- 验证 – Asp.Net MVC:子请求的执行失败.请查看I
- entity-framework – 如果EF 5,如何定义自定义命
- asp.net-mvc – 为一个MVC视图使用两个强类型模型
