Поддержка ключа API IdentityServer4

У меня 3 проекта в Visual Studio.

  1. Сервер идентификации
  2. Сайт API
  3. Угловой 2 передок

Я использую IdentityServer4 с ASP.NET Core Identity и Entity Framework. Пока все работает отлично.

Теперь я хочу добавить возможность пользователям генерировать ключ API, чтобы пользователь мог звонить на наш сервер API через свой сервер и просто передавать ключ API. Это затем (каким-то образом) аутентифицирует пользователя и сгенерирует токен доступа, используемый моим API для авторизации. Поддерживает ли IdentityServer4 создание ключей API для каждого пользователя? Я знаю, что есть секреты клиента, которые я реализовал, но они только идентифицируют клиента. Мне тоже нужно знать пользователя, чтобы я знал, что ему разрешено делать (используя для этого роли прямо сейчас).


person 206mph    schedule 02.03.2017    source источник
comment
В чем разница между ключом API для каждого пользователя и паролем пользователя?   -  person Mashton    schedule 02.03.2017
comment
Хороший вопрос. Ключ API можно использовать без указания имени пользователя и пароля пользователя в вызове API. Я изучаю это только для того, чтобы предоставить внешним разработчикам опыт, аналогичный использованию API Google, Swipe, StormPath и многих других поставщиков API.   -  person 206mph    schedule 02.03.2017
comment
Есть обновления по этому поводу? Поддерживает ли IdentityServer4 ключи Api?   -  person Hanna Holasava    schedule 22.06.2020
comment
Есть новости по этому поводу? Принятый ответ не отвечает на вопрос, упомянутый @ 206mph.   -  person Yanal-Yves Fargialla    schedule 04.09.2020


Ответы (1)


IdentityServer - это платформа и размещаемый компонент, который позволяет реализовать единый вход и контроль доступа для современных веб-приложений и API с использованием таких протоколов, как OpenID Connect и OAuth2. Он поддерживает широкий спектр клиентов, таких как мобильные, веб-приложения, SPA-приложения и настольные приложения, и может быть расширен для интеграции в новые и существующие архитектуры. в вашем классе запуска:

     public void ConfigureServices(IServiceCollection services)
                {
                    var source = System.IO.File.ReadAllText("MyCertificate.b64cert");
                    var certBytes = Convert.FromBase64String(source);
                    var certificate = new X509Certificate2(certBytes, "password");

                    var builder = services.AddIdentityServer(options =>
                    {
                        options.SigningCertificate = certificate;
                        options.RequireSsl = false; // should be true
                    });
             JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        app.UseIdentityServerAuthentication(options =>
        {
            options.Authority = "http://localhost:5000";
            options.ScopeName = "openid";
            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge = true;
        });
                    builder.AddInMemoryClients(Clients.Get());
                    builder.AddInMemoryScopes(Scopes.Get());
                    builder.AddInMemoryUsers(Users.Get());
                }

            public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
                    {
                        loggerFactory.AddConsole(LogLevel.Verbose);
                        loggerFactory.AddDebug(LogLevel.Verbose);
                        app.UseIdentityServer();
                    }

создать класс клиентов

public class Clients
{
    public static IEnumerable<Client> Get()
    {
        return new[]
        {
            new Client
            {
                ClientId = "myapi",
                ClientSecrets = new List<Secret>
                {
                    new Secret("secret".Sha256())
                },
                ClientName = "your api",
                Flow = Flows.ResourceOwner,
                AllowedScopes =
                {
                    Constants.StandardScopes.OpenId,
                    "read"
                },
                Enabled = true
            }
        };
    }
}

объемы

public class Scopes
{
    public static IEnumerable<Scope> Get()
    {
        return new[]
        {
            StandardScopes.OpenId,
            StandardScopes.Profile,
            StandardScopes.OfflineAccess,
            new Scope {Name = "advanced", DisplayName = "Advanced Options"}
        };
    }
}

контролер

[Route("api/[controller]")]
public class SomeController : Controller
{
    [HttpGet]
    [Authorize]
    public IEnumerable<string> Get()
    {
        return new[] { "value1", "value2" };
    }

    [HttpGet("{id}")]
    [Authorize]
    public string Get(int id)
    {
        return "value";
    }
}

как только это будет настроено, вы можете выдать токен аутентификации JWT, который затем пользователь может использовать в своем заголовке авторизации.

создать генерирующий класс

private async Task GenerateToken(HttpContext context)
{
    var username = context.Request.Form["username"];
    var password = context.Request.Form["password"];

    var identity = await GetIdentity(username, password);
    if (identity == null)
    {
        context.Response.StatusCode = 400;
        await context.Response.WriteAsync("Invalid username or password.");
        return;
    }

    var now = DateTime.UtcNow;

    // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
    // You can add other claims here, if you want:
    var claims = new Claim[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, username),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Iat, now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
    };

    // Create the JWT and write it to a string
    var jwt = new JwtSecurityToken(
        issuer: _options.Issuer,
        audience: _options.Audience,
        claims: claims,
        notBefore: now,
        expires: now.Add(_options.Expiration),
        signingCredentials: _options.SigningCredentials);
    var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

    var response = new
    {
        access_token = encodedJwt,
        expires_in = (int)_options.Expiration.TotalSeconds
    };

    // Serialize and return the response
    context.Response.ContentType = "application/json";
    await context.Response.WriteAsync(JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }));
}

создайте свое промежуточное ПО:

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace SimpleTokenProvider
{
    public class TokenProviderMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly TokenProviderOptions _options;

        public TokenProviderMiddleware(
            RequestDelegate next,
            IOptions<TokenProviderOptions> options)
        {
            _next = next;
            _options = options.Value;
        }

        public Task Invoke(HttpContext context)
        {
            // If the request path doesn't match, skip
            if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))
            {
                return _next(context);
            }

            // Request must be POST with Content-Type: application/x-www-form-urlencoded
            if (!context.Request.Method.Equals("POST")
               || !context.Request.HasFormContentType)
            {
                context.Response.StatusCode = 400;
                return context.Response.WriteAsync("Bad request.");
            }

            return GenerateToken(context);
        }
    }
}

и, наконец, подключите ваше промежуточное ПО для генерации токенов в вашем startup.cs

app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
person Marcus    schedule 02.03.2017
comment
Спасибо за весь код! Однако это генерирует токен доступа из того, что я могу сказать по коду. Я новичок в этом типе безопасности, поэтому, пожалуйста, оставайтесь со мной. Мое текущее решение уже создает и передает токены доступа, и это здорово. Однако, если вы перейдете в консоль разработчика Google, вы можете создать ключи API, которые позволят вам получить доступ к их API с помощью ключа (а не токена доступа). Пример ключа: AIzaSyBeOqHuSDFjHrpZWCyRWgT3nzIZHkWCjrRg. Это намного короче токена доступа. У каждого пользователя может быть несколько проблем с ключами API для каждого из своих приложений, которые могут его использовать. Я не знаю, как их создать. - person 206mph; 03.03.2017
comment
Ах, извините за это. Я предлагаю затем создать для этого вашего собственного провайдера. Создайте и сохраните коды base.64 в таблице, которая соответствует идентификатору пользователя. Затем при обращении к ur API он проверит, активен ли код, существует ли и имеет ли соответствующие разрешения. - person Marcus; 03.03.2017
comment
Если вы хотите просто создать ключи, используйте sha256 () - person Marcus; 03.03.2017
comment
@ 206mph вы просто хотите сгенерировать ключи? - person Marcus; 05.03.2017
comment
@Marcus, не могли бы вы уточнить и предоставить образец кода? Как API проверяет, активен ли код? - person Yanal-Yves Fargialla; 04.09.2020
comment
@ Yanal-YvesFargialla Далее, я думаю, что создание нового вопроса для этой темы - следующий шаг здесь. Как API проверяет, активен ли код, это то, что обрабатывает промежуточное ПО. с оформлением открытых конечных точек в вашем приложении. Identity Server должен знать, какие API-интерфейсы и их соответствующие конечные точки авторизованы IdentityServer. Вам необходимо установить объем авторизации. - person Marcus; 15.09.2020