我正在尝试在 .NET core 8 Web API 应用程序中探索基于身份令牌的身份验证。我能够注册用户、生成和存储令牌。但是,当我尝试访问授权 api 时,它失败了,重定向到 /Account/login 端点。请注意,我已为我自己的 API/操作添加了 [Authorize] attr。根据我的分析,它重定向到 /Account/Login 因为 API 没有这个端点,因此它抛出 404 而不是 401。我担心的是为什么它甚至无法进行身份验证。
我尝试了多种配置来使其工作,但没有一个有帮助, 请在此指导。
注意B 我成功地能够使用 Jwt 令牌,我想使用默认身份进行令牌管理而不是 JWT。参考了docs,但我在某处遗漏了它。
代码: 程序
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedAccount = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); // Ensures to use default AspNet token providers
builder.Services.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme); // tried few options but same error
builder.Services.AddAuthorization();
/* This is working as expected
var issuer = builder.Configuration.GetSection("Jwt:Issuer").Get<string>();
var audience = builder.Configuration.GetSection("Jwt:Audience").Get<string>();
var secretKey = builder.Configuration.GetSection("Jwt:SecretKey").Get<string>();
builder.Services.AddAuthentication(
options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(
options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = issuer,
ValidAudience = audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
};
});
*/
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IJwtService, JwtService>();
builder.Services.AddScoped<IAspTokenService, AspTokenService>();
builder.Services.AddControllers();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
db.Database.Migrate();
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
控制器:
[HttpPost("register")]
[AllowAnonymous]
public async Task<ActionResult> Register([FromBody] RegisterModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var appUser = new ApplicationUser() { UserName = model.UserId, Email = model.Email, NewAddress = model.Address };
var result = await _userManager.CreateAsync(appUser, model.Password);
if (result.Succeeded)
{
//var token = _jwtService.GenerateToken(model.UserId);
var token = await _aspTokenService.GenerateAndStoreTokenAsync(appUser.UserName);
return Ok(token);
}
return BadRequest(result.Errors);
}
[HttpPost("login")]
[AllowAnonymous]
public async Task<ActionResult> Login([FromBody] LoginModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await _userManager.FindByNameAsync(model.UserId);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
//var token = _jwtService.GenerateToken(user.UserName);
var token = await _aspTokenService.GenerateAndStoreTokenAsync(user.UserName);
return Ok(token);
}
return Unauthorized();
}
[HttpGet("securedata")]
[Authorize]
public ActionResult GetSecureData()
{
string token = string.Empty;
var usersCliams = User.Identity as ClaimsIdentity;
foreach (var claim in usersCliams?.Claims)
{
if ("Id".Equals(claim.Type))
{
token = claim.Value.ToString();
break;
}
}
return Ok(new { Message = $"Id {token}" });
}
服务
private UserManager<ApplicationUser> _userManager;
public AspTokenService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<TokenDto> GenerateAndStoreTokenAsync(string username)
{
if (string.IsNullOrEmpty(username))
{
return null;
}
var user = await _userManager.FindByNameAsync(username);
if (user == null)
{
return null;
}
var token = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, user.Id);
await _userManager.SetAuthenticationTokenAsync(user, TokenOptions.DefaultProvider, user.Id, token);
return new TokenDto { Token = token };
}
public async Task<TokenDto> GetTokenAsync(string username)
{
if (string.IsNullOrEmpty(username))
{
return null;
}
var user = await _userManager.FindByNameAsync(username);
if (user == null)
{
return null;
}
var token = await _userManager.GetAuthenticationTokenAsync(user, TokenOptions.DefaultProvider, user.Id);
return new TokenDto { Token = token };
}
其他
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
public class ApplicationUser : IdentityUser
{
public string? NewAddress { get; set; }
}
数据库表映射 - 检查用户Manu123456,忽略其他两个
在 .net 8 中,现在有用于 asp.net 身份的内置 jwt 端点。
安装包
Microsoft.AspNetCore.Identity.EntityFrameworkCore
AddIdentity
,尝试使用以下代码
builder.Services.AddIdentityCore<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultTokenProviders();
...
app.MapIdentityApi<IdentityUser>();
参考:https://andrewlock.net/exploring-the-dotnet-8-preview-introducing-the-identity-api-endpoints/