Как написать клиент веб-API OAuth2 в Asp.net MVC

Мы разработали набор веб-API (REST), которые защищены сервером авторизации. Сервер авторизации выдал идентификатор клиента и секрет клиента. Их можно использовать для получения токена доступа. Действительный токен может использоваться при последующих вызовах на серверы ресурсов (REST API).

Я хочу написать веб-клиент (Asp.net MVC 5), который будет использовать API. Есть ли пакет nuget, который я могу загрузить, который поможет мне реализовать поток клиента OAuth2? Может ли кто-нибудь привести меня к хорошему примеру реализации клиента потока OAuth2 (написанного в asp.net MVC)?

Обновление Я смог получить токен доступа, используя блок кода ниже, но то, что я хочу, - это "учетные данные клиента" oauth 2, где мне не нужно вводить логин и пароли. Код, который у меня есть сейчас:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType("ClientCookie");

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = "ClientCookie",
            CookieName = CookieAuthenticationDefaults.CookiePrefix + "ClientCookie",
            ExpireTimeSpan = TimeSpan.FromMinutes(5)
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,                
            SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
            ClientId = ConfigurationManager.AppSettings["AuthServer:ClientId"],
            ClientSecret = ConfigurationManager.AppSettings["AuthServer:ClientSecret"],
            RedirectUri = ConfigurationManager.AppSettings["AuthServer:RedirectUrl"],
            Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://identityserver.com/oauth2/authorize",
                TokenEndpoint = "https://identityserver.com/oauth2/token"                                        
            },

            //ResponseType = "client_credentials", // Doesn't work
            ResponseType = "token",

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = notification =>
                {
                    if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal))
                    {
                        notification.HandleResponse();

                        notification.Response.Redirect("/");
                    }

                    return Task.FromResult<object>(null);
                },

                AuthorizationCodeReceived = async notification =>
                {
                    using (var client = new HttpClient())
                    {
                        //var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);
                        String tokenEndPoint = "https://identityserver.com/oauth2/token";

                        //var request = new HttpRequestMessage(HttpMethod.Post, configuration.TokenEndpoint);
                        var request = new HttpRequestMessage(HttpMethod.Post, tokenEndPoint);
                        request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
                            { OpenIdConnectParameterNames.ClientId, notification.Options.ClientId },
                            { OpenIdConnectParameterNames.ClientSecret, notification.Options.ClientSecret },
                            { OpenIdConnectParameterNames.Code, notification.ProtocolMessage.Code },
                            { OpenIdConnectParameterNames.GrantType, "authorization_code" },
                            { OpenIdConnectParameterNames.RedirectUri, notification.Options.RedirectUri }
                        });

                        var response = await client.SendAsync(request, notification.Request.CallCancelled);
                        response.EnsureSuccessStatusCode();

                        var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

                        // Add the access token to the returned ClaimsIdentity to make it easier to retrieve.
                        notification.AuthenticationTicket.Identity.AddClaim(new Claim(
                            type: OpenIdConnectParameterNames.AccessToken,
                            value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken)));
                    }
                }
            }
        });


    }
}

Ответ 1

Чтобы поддерживать тип предоставления учетных данных клиента, наилучшим вариантом является, возможно, прямое использование HttpClient:

var request = new HttpRequestMessage(HttpMethod.Post, "http://server.com/token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
    { "client_id", "your client_id" },
    { "client_secret", "your client_secret" },
    { "grant_type", "client_credentials" }
});

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = payload.Value<string>("access_token");

Для интерактивных потоков (например, потока кода авторизации) существуют два лучших подхода: