自去年下半年以来,已经阅读了LinkedIn,终于终于使我们能够检索到我当前未能登录的当前登录用户的电子邮件地址。我已经阅读了在SO以及其他地方可以找到的所有文章,据我所知,我的代码应该可以正常工作。它在其他所有字段中都可以正常返回,

但是,电子邮件地址字段始终为空。

这是我的LinkedInClient类;

public class LinkedInClient2 : OAuthClient
{
    public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription
    {
        AccessTokenEndpoint =
            new MessageReceivingEndpoint(
                "https://api.linkedin.com/uas/oauth/accessToken",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        RequestTokenEndpoint =
            new MessageReceivingEndpoint(
                "https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        UserAuthorizationEndpoint =
            new MessageReceivingEndpoint(
                "https://www.linkedin.com/uas/oauth/authenticate",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
        ProtocolVersion = ProtocolVersion.V10a
    };

    public LinkedInClient2(string consumerKey, string consumerSecret, IConsumerTokenManager tokenManager)
        : base("linkedIn", LinkedInServiceDescription, tokenManager)
    {
    }

    [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,email-address,headline,industry,summary,picture-url)";
        string accessToken = response.AccessToken;
        var profileEndpoint = new MessageReceivingEndpoint(ProfileRequestUrl, HttpDeliveryMethods.GetRequest);
        HttpWebRequest request = this.WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken);

        try
        {
            using (WebResponse profileResponse = request.GetResponse())
            {
                using (Stream responseStream = profileResponse.GetResponseStream())
                {
                    XDocument document = LoadXDocumentFromStream(responseStream);
                    string userId = document.Root.Element("id").Value;

                    // User Profile Fields - https://developer.linkedin.com/documents/profile-fields
                    string firstName = document.Root.Element("first-name").Value;
                    string lastName = document.Root.Element("last-name").Value;
                    string userName = document.Root.Element("email-address").Value; // <<<<<< ERROR - always empty

                    var extraData = new Dictionary<string, string>();
                    extraData.Add("accesstoken", accessToken);
                    extraData.Add("name", userName);
                    extraData.AddDataIfNotEmpty(document, "picture-url");
                    extraData.AddDataIfNotEmpty(document, "location");
                    extraData.AddDataIfNotEmpty(document, "headline");
                    extraData.AddDataIfNotEmpty(document, "summary");
                    extraData.AddDataIfNotEmpty(document, "industry");

                    return new AuthenticationResult(
                        isSuccessful: true, provider: this.ProviderName, providerUserId: userId, userName: userName, extraData: extraData);
                }
            }
        }
        catch (Exception exception)
        {
            return new AuthenticationResult(exception);
        }
    }

    internal static XDocument LoadXDocumentFromStream(Stream stream)
    {
        const int MaxChars = 0x10000; // 64k

        XmlReaderSettings settings = new XmlReaderSettings()
        {
            MaxCharactersInDocument = MaxChars
        };
        return XDocument.Load(XmlReader.Create(stream, settings));
    }
}


}

我意识到应该将scope=r_emailaddress添加到RequestTokenEndpoint(我有),但是从提琴手的痕迹中我什至看不到该端点已被提取。基本上,它只使用AccessTokenEndpoint大概与我的问题有关。

这大致就是我的ASP.Net MVC4.5控制器的外观;

    [AllowAnonymous]
    public virtual ActionResult LinkedIn(string returnUrl)
    {
        var tokenMgr = new RepoOAuthTokenManager(_iOtk, LinkedInAppKey, LinkedInAppSecret);
        var iacp = new LinkedInClient2(LinkedInAppKey, LinkedInAppSecret, tokenMgr); // if none specified, LinkedInClient uses the AuthenticationOnlyCookieOAuthTokenManager which doesn't work for APIs
        var ioadp = new MyOauthDataProvider();
        var oasm = new OpenAuthSecurityManager(this.HttpContext, iacp, ioadp);

        var redirectUri = Url.ActionFullyQualified(this.nameof(c => c.LinkedIn(null)), null, new RouteValueDictionary(new { returnUrl = returnUrl }));
        AuthenticationResult ar = oasm.VerifyAuthentication(redirectUri);
        if (ar.Error == null)
        {
            if (ar.IsSuccessful)
                DoSomethingResultingInRedirect(redirectUri); // OK
            else
                oasm.RequestAuthentication(redirectUri);
        }
        else
            ModelState.AddModelError("", ar.Error.Message);

        return View(this.nameof(c=>c.Login(null)));
    }//LinkedIn


我不能说我完全理解DotNetOpenAuth中的可扩展性机制,并且我可能会误解某些东西,所以我希望了解一些指针。

我在某处错过了一步吗?

最佳答案

我有两个解决方案,尽管我仍然不明白如何使我现有的代码按我期望的那样工作,但是希望这可以对其他人有所帮助。

(1)我去Making it easier for you to add default member permissions并单击API admin页面。



您可以在此处选择默认情况下要请求的范围。直到我单击一个按"[x] Make this permanent".字样的框(现在消失了),它才起作用。一旦完成,便开始按期望的方式填充email-address字段。

(2)我尝试使用OAuth2 URL代替信息here,它似乎有效。我还发现了一个OAuth2客户端here的实现,这看起来是一个不错的开始。我怀疑从长远来看,OAuth2升级(一旦规格更加静态)会带来更好的总体里程。

尽管目前,我已经绝望了,但是仍然欢迎其他答案!

关于c# - LinkedIn OAUTH-仍然无法使用DotNetOpenAuth.AspNet获取电子邮件地址,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17924170/

10-13 02:49