IdentityServer4 API 关键支持
IdentityServer4 API Key Support
我在 Visual Studio 中有 3 个项目。
- 身份服务器
- API 站点
- Angular 2前端
我正在使用具有 ASP.NET Core Identity 和 Entity Framework 的 IdentityServer4。目前一切正常。
现在,我想为用户添加生成 API 密钥的功能,这样用户就可以通过他们的服务器调用我们的 API 服务器并简单地传入 API 钥匙。然后,这将(以某种方式)对用户进行身份验证并生成我的 API 用于授权的访问令牌。 IdentityServer4 是否支持为每个用户生成 API 密钥?我知道有客户端机密,我已经实现了但只能识别客户端。我也需要了解用户,这样我才能知道用户有权做什么(现在就使用角色)。
IdentityServer is a framework and a hostable component that allows
implementing single sign-on and access control for modern web
applications and APIs using protocols like OpenID Connect and OAuth2.
It supports a wide range of clients like mobile, web, SPAs and desktop
applications and is extensible to allow integration in new and
existing architectures.
in your startup class:
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();
}
创建客户class
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 身份验证令牌,用户随后可以在其授权中使用该令牌header
创建生成器class
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));
我在 Visual Studio 中有 3 个项目。
- 身份服务器
- API 站点
- Angular 2前端
我正在使用具有 ASP.NET Core Identity 和 Entity Framework 的 IdentityServer4。目前一切正常。
现在,我想为用户添加生成 API 密钥的功能,这样用户就可以通过他们的服务器调用我们的 API 服务器并简单地传入 API 钥匙。然后,这将(以某种方式)对用户进行身份验证并生成我的 API 用于授权的访问令牌。 IdentityServer4 是否支持为每个用户生成 API 密钥?我知道有客户端机密,我已经实现了但只能识别客户端。我也需要了解用户,这样我才能知道用户有权做什么(现在就使用角色)。
IdentityServer is a framework and a hostable component that allows implementing single sign-on and access control for modern web applications and APIs using protocols like OpenID Connect and OAuth2. It supports a wide range of clients like mobile, web, SPAs and desktop applications and is extensible to allow integration in new and existing architectures. in your startup class:
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();
}
创建客户class
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 身份验证令牌,用户随后可以在其授权中使用该令牌header
创建生成器class
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));