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; } } } } (编辑:4S站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ASP.NET虚拟路径映射到另一个不允许的应用程序
- asp.net-core – 编译netcoreapp1.0,代码包含#if!NETSTAND
- asp.net – 如何使用Fiddler编辑HTTP请求
- asp.net – Ajax上的Identity Server 3 – 401而不是302
- asp.net-mvc – 尝试创建类型为’TypeNewsController’的控
- asp.net – 如何在页面加载时以“添加新”模式进行编程设置
- asp.net-mvc-3 – 在ASP.NET MVC 3中覆盖/禁用授权
- asp.net – “2015年4月20日Google帐户的OpenID2已经消失”
- asp.net-mvc-3 – MVC 3 $.ajax – 响应似乎是从部分视图缓
- asp.net-mvc-3 – 如何关闭我的整个ASP.NET MVC 3网站的缓存
- asp.net-mvc-3 – ASP.net MVC – 模型绑定不包括
- asp.net-mvc – MVC导航到不同的控制器视图
- asp.net-mvc – .Net 4.5.1框架的maxRequestLeng
- asp.net – 部分视图呈现按钮点击
- asp.net – WebBrowsable vs个性化Web部件
- 在asp.net c#应用程序中使用Graphviz Dll
- asp.net+js实现批量编码与解码的方法
- asp.net-mvc-3 – Orchard CMS DataAnnotations
- asp.net – Html.Partial()跳过控制器动作
- asp.net-mvc – 有条件地在webgrid中显示图像 –