asp.net-mvc-4 – MVC4/DotNetOpenAuth中的自定义OAuth客户端 – 缺少访问令牌密钥
|
我目前正在为我的应用程序实现Dropbox OAuth客户端.直到我结束,这是一个相当轻松的过程.一旦我获得授权,当我尝试访问用户数据时,我从Dropbox返回401关于该令牌无效的消息.我在Dropbox论坛上问过,看起来我的请求缺少Dropbox返回的access_token_secret.我能够使用Fiddler来挖掘秘密,并将其添加到我的请求网址,它工作正常,所以这绝对是问题所在.那么为什么DotNetOpenAuth在返回访问令牌时不返回访问令牌秘密? 供参考,我的代码: public class DropboxClient : OAuthClient
{
public static readonly ServiceProviderDescription DropboxServiceDescription = new ServiceProviderDescription
{
RequestTokenEndpoint = new MessageReceivingEndpoint("https://api.dropbox.com/1/oauth/request_token",HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.dropbox.com/1/oauth/authorize",AccessTokenEndpoint = new MessageReceivingEndpoint("https://api.dropbox.com/1/oauth/access_token",TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new PlaintextSigningBindingElement() }
};
public DropboxClient(string consumerKey,string consumerSecret) :
this(consumerKey,consumerSecret,new AuthenticationOnlyCookieOAuthTokenManager())
{
}
public DropboxClient(string consumerKey,string consumerSecret,IOAuthTokenManager tokenManager) :
base("dropbox",DropboxServiceDescription,new SimpleConsumerTokenManager(consumerKey,tokenManager))
{
}
protected override DotNetOpenAuth.AspNet.AuthenticationResult VerifyAuthenticationCore(DotNetOpenAuth.OAuth.Messages.AuthorizedTokenResponse response)
{
var profileEndpoint = new MessageReceivingEndpoint("https://api.dropbox.com/1/account/info",HttpDeliveryMethods.GetRequest);
HttpWebRequest request = this.WebWorker.PrepareAuthorizedRequest(profileEndpoint,response.AccessToken);
try
{
using (WebResponse profileResponse = request.GetResponse())
{
using (Stream profileResponseStream = profileResponse.GetResponseStream())
{
using (StreamReader reader = new StreamReader(profileResponseStream))
{
string jsonText = reader.ReadToEnd();
JavaScriptSerializer jss = new JavaScriptSerializer();
dynamic jsonData = jss.DeserializeObject(jsonText);
Dictionary<string,string> extraData = new Dictionary<string,string>();
extraData.Add("displayName",jsonData.display_name ?? "Unknown");
extraData.Add("userId",jsonData.uid ?? "Unknown");
return new DotNetOpenAuth.AspNet.AuthenticationResult(true,ProviderName,extraData["userId"],extraData["displayName"],extraData);
}
}
}
}
catch (WebException ex)
{
using (Stream s = ex.Response.GetResponseStream())
{
using (StreamReader sr = new StreamReader(s))
{
string body = sr.ReadToEnd();
return new DotNetOpenAuth.AspNet.AuthenticationResult(new Exception(body,ex));
}
}
}
}
}
解决方法当我在寻找类似问题的解决方案时,我发现了你的问题.我通过制作2个新类来解决它,你可以在这个 coderwall post中阅读.我还会在这里复制并粘贴完整帖子: DotNetOpenAuth.AspNet 401未经授权的错误和持久访问令牌秘密修复 在设计我们的云电子书管理器QuietThyme时,我们知道每个人都讨厌像我们一样创建新帐户.我们开始寻找可以利用社交登录的OAuth和OpenId库.我们最终使用DotNetOpenAuth.AspNet库进行用户身份验证,因为它支持Microsoft,Twitter,Facebook,LinkedIn和Yahoo等许多其他人.虽然我们有一些问题需要设置,但最后我们只需要进行一些小的自定义来完成大部分工作(在previous coderwall post中描述).我们注意到,与其他所有人不同,LinkedIn客户端不会进行身份验证,从DotNetOpenAuth返回401 Unauthorized Error.很快就发现这是由于签名问题,在查看源代码后,我们能够确定检索到的AccessToken机密未与经过身份验证的配置文件信息请求一起使用. 它实际上是有道理的,OAuthClient类不包含检索的访问令牌秘密的原因是它通常不需要用于身份验证,这是ASP.NET OAuth库的主要目的. 我们需要在用户登录后对api进行身份验证请求,以检索一些标准配置文件信息,包括电子邮件地址和全名.我们能够通过暂时使用InMemoryOAuthTokenManager来解决这个问题. public class LinkedInCustomClient : OAuthClient
{
private static XDocument LoadXDocumentFromStream(Stream stream)
{
var settings = new XmlReaderSettings
{
MaxCharactersInDocument = 65536L
};
return XDocument.Load(XmlReader.Create(stream,settings));
}
/// Describes the OAuth service provider endpoints for LinkedIn.
private static readonly ServiceProviderDescription LinkedInServiceDescription =
new ServiceProviderDescription
{
AccessTokenEndpoint =
new MessageReceivingEndpoint("https://api.linkedin.com/uas/oauth/accessToken",HttpDeliveryMethods.PostRequest),RequestTokenEndpoint =
new MessageReceivingEndpoint("https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress",UserAuthorizationEndpoint =
new MessageReceivingEndpoint("https://www.linkedin.com/uas/oauth/authorize",TamperProtectionElements =
new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },//ProtocolVersion = ProtocolVersion.V10a
};
private string ConsumerKey { get; set; }
private string ConsumerSecret { get; set; }
public LinkedInCustomClient(string consumerKey,string consumerSecret)
: this(consumerKey,new AuthenticationOnlyCookieOAuthTokenManager()) { }
public LinkedInCustomClient(string consumerKey,IOAuthTokenManager tokenManager)
: base("linkedIn",LinkedInServiceDescription,tokenManager))
{
ConsumerKey = consumerKey;
ConsumerSecret = consumerSecret;
}
//public LinkedInCustomClient(string consumerKey,string consumerSecret) :
// base("linkedIn",consumerKey,consumerSecret) { }
/// Check if authentication succeeded after user is redirected back from the service provider.
/// The response token returned from service provider authentication result.
[SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes",Justification = "We don't care if the request fails.")]
protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response)
{
// See here for Field Selectors API http://developer.linkedin.com/docs/DOC-1014
const string profileRequestUrl =
"https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,industry,summary,email-address)";
string accessToken = response.AccessToken;
var profileEndpoint =
new MessageReceivingEndpoint(profileRequestUrl,HttpDeliveryMethods.GetRequest);
try
{
InMemoryOAuthTokenManager imoatm = new InMemoryOAuthTokenManager(ConsumerKey,ConsumerSecret);
imoatm.ExpireRequestTokenAndStoreNewAccessToken(String.Empty,String.Empty,accessToken,(response as ITokenSecretContainingMessage).TokenSecret);
WebConsumer w = new WebConsumer(LinkedInServiceDescription,imoatm);
HttpWebRequest request = w.PrepareAuthorizedRequest(profileEndpoint,accessToken);
using (WebResponse profileResponse = request.GetResponse())
{
using (Stream responseStream = profileResponse.GetResponseStream())
{
XDocument document = LoadXDocumentFromStream(responseStream);
string userId = document.Root.Element("id").Value;
string firstName = document.Root.Element("first-name").Value;
string lastName = document.Root.Element("last-name").Value;
string userName = firstName + " " + lastName;
string email = String.Empty;
try
{
email = document.Root.Element("email-address").Value;
}
catch(Exception)
{
}
var extraData = new Dictionary<string,string>();
extraData.Add("accesstoken",accessToken);
extraData.Add("name",userName);
extraData.AddDataIfNotEmpty(document,"headline");
extraData.AddDataIfNotEmpty(document,"summary");
extraData.AddDataIfNotEmpty(document,"industry");
if(!String.IsNullOrEmpty(email))
{
extraData.Add("email",email);
}
return new AuthenticationResult(
isSuccessful: true,provider: this.ProviderName,providerUserId: userId,userName: userName,extraData: extraData);
}
}
}
catch (Exception exception)
{
return new AuthenticationResult(exception);
}
}
}
(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc-3 – 如何在ASP.NET MVC 3中更新EF 4实体?
- asp.net – 在Web.config帮助中定义tagPrefixes
- asp.net-mvc – 在MVC身份(2.0.1)中的regenerateIdentity/v
- 使用ASP.NET MVC进行Windows身份验证
- asp.net-mvc – 在mvc中使用带有错误消息的资源
- asp.net-mvc – 如何将httppostedfilebase转换为String数组
- asp.net-mvc-3 – 为什么两个类,视图模型和域模型?
- asp.net-mvc – MVC ELMAH和SQL Azure
- asp.net – 全局ASAX中的错误:文件不存在
- 休息 – ASP.NET Web API授权和身份验证
- 关闭一个子目录的ASP.Net WebForms身份验证
- asp.net-mvc-4 – 使用MVC 4 SimpleMembership与
- asp.net-mvc – 为什么这个MVC路由不起作用?
- asp.net-mvc-3 – 在同一父视图上多次使用一个部
- asp.net-mvc – 以表格形式上传图片并在MVC 4上显
- asp.net – jQuery AJAX vs. UpdatePanel
- asp.net-mvc – MVC Ajax.BeginForm替换奇怪的行
- 为什么我需要停止使用%= ...%来渲染并开始使用
- asp.net – 通过Web服务访问连接字符串
- asp.net – 为什么Web架构松散耦合?
