我们正在启动一个新的 Web 应用程序,该应用程序将托管在我们的客户基础设施中。由于这是一个将存在一段时间并作为许多未来产品的基础的解决方案,我们希望拥有一个面向未来的安全性,这将是未来的 poff (SSO / MFA),但这就像在3年。对于我们的客户来说,我们依赖一些标准很重要,所以我考虑使用 OpenId。
该解决方案将基于 ASP.NET Core + Angular。所以我发现有 ASP.NET Core Identity,已经与 OpenID Connect 兼容,但后来我看到here Microsoft 推荐 Duende Identity Server (IdentityServer4)。
问题是我们是一个小团队,构建一个小型应用程序,但在一个大企业中,所以必须选择许可版本。另一个问题是,由于是我们的客户自己部署应用程序,我们无法控制部署多少服务器,因此我们必须选择“企业”订阅,这完全超出了我们的预算。
尽管如此,我们仍然希望我们仍然可以使用 ASP.NET Core Identity 连接到不同的用户源、管理应用程序的权限、使用控制器上的属性。
那么,如何在不使用 IdentityServer 的情况下使用 ASP.NET Core Identity?
根据 MSFT 文档
ASP.NET Core Identity 添加了用户界面 (UI) 登录功能 ASP.NET Core Web 应用程序。
要保护 Web API 和 SPA,请使用其中之一 以下:
- Azure 活动目录 Azure
- Active Directory B2C(Azure AD B2C)
- 身份服务器4
所以他们首先提供他们的云解决方案。
Identityserver4 免费版本仍然受支持,直到 .Net Core 3.1 EOL。
作为一个没有任何预定义 EOL 的免费选项,您可以尝试使用此 OpenIddict 示例作为您的解决方案的起点,但是它还有更多的空白需要您自己填补。
这里解释了为什么 MSFT 不在他们的文档中提供它(剧透:见上文)
您可以使用纯 ASP.NET Core,无需
IdentityServer
。
如果您使用相同的后端进行身份验证和 API,则非常容易。
示例(从源复制):
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.MapGet("/security/getMessage", () => "Hello World!").RequireAuthorization();
app.MapPost("/security/createToken",
[AllowAnonymous] (User user) =>
{
if (user.UserName == "joydip" && user.Password == "joydip123")
{
var issuer = builder.Configuration["Jwt:Issuer"];
var audience = builder.Configuration["Jwt:Audience"];
var key = Encoding.ASCII.GetBytes
(builder.Configuration["Jwt:Key"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Email, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti,
Guid.NewGuid().ToString())
}),
Expires = DateTime.UtcNow.AddMinutes(5),
Issuer = issuer,
Audience = audience,
SigningCredentials = new SigningCredentials
(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha512Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtToken = tokenHandler.WriteToken(token);
var stringToken = tokenHandler.WriteToken(token);
return Results.Ok(stringToken);
}
return Results.Unauthorized();
});
app.UseAuthentication();
app.UseAuthorization();
app.Run();
另请参阅: