在.NET Core 2.0中如何添加LinkedIn OAuth?

9

我正在使用dotnet core,希望在我的网站上设置LinkedIn身份验证。由于没有像Facebook、Google和Twitter那样的默认认证生成器,因此我决定使用以下通用实现:

services.AddAuthentication().AddOAuth("LinkedIn", 
            c =>
            {
                c.ClientId = Configuration["linkedin-app-id"];
                c.ClientSecret = Configuration["linkedin-app-secret"];
                c.Scope.Add("r_basicprofile");
                c.Scope.Add("r_emailaddress");
                c.CallbackPath = "/signin-linkedin";
                c.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
                c.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
                c.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)";
})

我遇到了一个问题,因为GetExternalLoginInfoAsync()为空,查看Identity ASP.net core源代码,发现是由于providerkey为空导致的。

以下是来自asp.net core代码:

var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var provider = items["LoginProvider"] as string;
if (providerKey == null || provider == null)
{
   return null;
}

问题是在LinkedIn声明中,我该在哪里添加ClaimTypes.NameIdentifier


在https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers中还有一个LinkedIn提供程序(目前是rc2-final版本)。如果您搜索AspNet.Security.OAuth.LinkedIn并确保选中包括预发布版本,就可以从nuget获取它。 - meldim
谢谢更新! - pedrommuller
2个回答

16
在这种情况下,您需要使用类似于此的OauthEvent手动预填每个声明:
.AddOAuth("LinkedIn", 
            c =>
            {
                c.ClientId = Configuration["linkedin-app-id"];
                c.ClientSecret = Configuration["linkedin-app-secret"];
                c.Scope.Add("r_basicprofile");
                c.Scope.Add("r_emailaddress");
                c.CallbackPath = "/signin-linkedin";
                c.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
                c.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
                c.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)";
                c.Events = new OAuthEvents
                {
                    OnCreatingTicket = async context =>
                    {
                        var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
                        request.Headers.Add("x-li-format", "json");

                        var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
                        response.EnsureSuccessStatusCode();
                        var user = JObject.Parse(await response.Content.ReadAsStringAsync());

                        var userId = user.Value<string>("id");
                        if (!string.IsNullOrEmpty(userId))
                        {
                            context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                        }

                        var formattedName = user.Value<string>("formattedName");
                        if (!string.IsNullOrEmpty(formattedName))
                        {
                            context.Identity.AddClaim(new Claim(ClaimTypes.Name, formattedName, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                        }

                        var email = user.Value<string>("emailAddress");
                        if (!string.IsNullOrEmpty(email))
                        {
                            context.Identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String,
                                context.Options.ClaimsIssuer));
                        }
                        var pictureUrl = user.Value<string>("pictureUrl");
                        if (!string.IsNullOrEmpty(pictureUrl))
                        {
                            context.Identity.AddClaim(new Claim("profile-picture", pictureUrl, ClaimValueTypes.String,
                                context.Options.ClaimsIssuer));
                        }
                    }
                };

            })

你在哪里找到了如何配置AddOAuth方法的信息? - botenvouwer
我不记得确切的内容,但这一页是我当时研究的几个页面之一:https://www.jerriepelser.com/blog/authenticate-oauth-aspnet-core-2/。据我所知,官方仓库中已经有一个LinkedIn的OAuth提供者,请检查一下。 - pedrommuller

0

使用NuGet包AspNet.Security.OAuth.Providers更简单,可以使用options.ClaimActions.MapJsonKey转换声明。

.AddLinkedIn(options =>
{
    var linkedInOptions = new Dictionary<string, string>();
    Configuration.Bind("LinkedIn", linkedInOptions);

    options.ClientId = linkedInOptions[nameof(options.ClientId)];
    options.ClientSecret = linkedInOptions[nameof(options.ClientSecret)];

    // Use v2 API
    options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
    options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";

    // This is already mapped by NuGet package
    //options.ClaimActions.MapJsonKey(OpenIdConnectConstants.Claims.Name, "formattedName");

请查看 https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/blob/dev/src/AspNet.Security.OAuth.LinkedIn/LinkedInAuthenticationOptions.cs


我唯一的问题是 options.Events.OnCreatingTicket 没有被调用。 - Andrii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接