首页 文章

IdentityServer4 API密钥支持

提问于
浏览
2

我在Visual Studio中有3个项目 .

  • Identity Server

  • API站点

  • 角2前端

我正在使用IdentityServer4与ASP.NET核心身份和实体框架 . 到目前为止,一切都很好 .

现在,我想为用户添加生成API密钥的功能,以便用户可以通过他们的服务器调用我们的API服务器,只需传入API密钥即可 . 然后(以某种方式)将对用户进行身份验证并生成我的API用于授权的访问令牌 . IdentityServer4是否支持为每个用户生成API密钥?我知道有客户机密,我已经实施但只能识别客户端 . 我也需要了解用户,所以我知道用户有权做什么(现在使用角色) .

1 回答

  • 6

    IdentityServer是一个框架和一个托管组件,允许使用OpenID Connect和OAuth2等协议为现代Web应用程序和API实现单点登录和访问控制 . 它支持广泛的客户端,如移动,Web,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();
                        }
    

    创建一个Clients类

    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身份验证令牌,然后用户可以在其Authorization标头中使用该令牌

    创建一个生成类

    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));
    

相关问题