3

自去年年底以来,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_emailaddressRequestTokenEndpoint(我拥有的),但是从提琴手的痕迹中我什至看不到那个端点被提取。基本上,它只有每个都使用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 中的可扩展性机制,我可能会误解一些东西,所以我很感激一些指示。

我在某处错过了一步吗?

4

2 回答 2

0

我有两个解决方案,虽然我仍然不明白如何让我现有的代码按我的预期工作,但希望这可以帮助其他人;

(1) 我去了使您更容易添加默认成员权限,然后单击API 管理页面。

OAuth 默认成员范围

在这里,您可以选择默认情况下要请求的范围。直到我单击了一个框(现在消失了),它才起作用,该框的措辞类似于"[x] Make this permanent".一旦我完成了,我开始按email-address预期填充该字段。

(2) 我尝试使用 OAuth2 URL,而不是从这里的信息,它似乎工作。我还在这里找到了一个 OAuth2 客户端的实现,这看起来是一个好的开始。我怀疑从长远来看,OAuth2 升级(一旦规范更加静态)将产生更好的整体里程。

虽然现在,我已经摆脱了绝望的深渊,但仍然欢迎其他答案!

于 2013-07-29T14:26:40.717 回答
0

我有一个类似的问题..也许这与你有关:

我的请求令牌调用是:

https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,member-url-resources,picture-url,location,public-profile-url,email-address )?格式=json

但json响应是:

array(8) {
  ["emailAddress"]=>
  string(18) "email@email.com"
  ["firstName"]=>
  string(3) "Tim"
  ...

请注意,在第一种情况下,电子邮件在第二个emailAddress中被命名为email-address

于 2013-11-06T09:18:52.833 回答