不记名令牌 401 错误 - asp.net 核心 3.1
401 error with bearer token - asp.net core 3.1
我无法使用 Asp.net Core 生成的令牌授权访问受保护的方法。
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApplicationSettings>
(Configuration.GetSection("ApplicationSettings"));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddScoped<IRepository<Course>, GenericRepository<Course>>();
services.AddRazorPages();
// CORS - Configuration
services.AddCors(opt =>
opt.AddPolicy("CorsPolicy", policy =>
policy.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "LMS Basic API",
Description = "LMS Diamond for api",
});
//c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
//{
// Name = "Authorization",
// Type = SecuritySchemeType.ApiKey,
// Scheme = "Bearer",
// BearerFormat = "JWT",
// In = ParameterLocation.Header,
// Description = "JWT Authorization header using the Bearer scheme."
//});
//c.AddSecurityRequirement(new OpenApiSecurityRequirement
//{
// {
// new OpenApiSecurityScheme
// {
// Reference = new OpenApiReference
// {
// Type = ReferenceType.SecurityScheme,
// Id = "Bearer"
// }
// },
// new string[] {}
// }
//});
});
// JWT Auth
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
//app.UseRewriter(new RewriteOptions()
// .AddRedirectToHttpsPermanent());
app.UseCors("CorsPolicy");
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "LMS Basic API");
c.RoutePrefix = string.Empty;
});
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
登录操作时生成令牌
var tokenDescripter = new SecurityTokenDescriptor
{
Subject = new System.Security.Claims.ClaimsIdentity(new Claim[] {
new Claim("UserID", user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddSeconds(20),
SigningCredentials = new SigningCredentials(new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(applicationSettings.JWT_Secret)),
SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescripter);
var token = tokenHandler.WriteToken(securityToken);
动作
[HttpGet]
[Authorize(AuthenticationSchemes = "Bearer")]
[Route("GetUserData")]
public async Task<IActionResult> GetUserData()
{
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return BadRequest();
}
return Ok(new
{
user.Id,
user.FullName,
user.Email,
});
}
我可以在 Postman 的 HTTP headers 中添加或不添加授权,我收到一个 "Unauthorized Exception - 401"
我已经检查了一些其他的Stack post和GitHub Post,看来我的配置没问题。
如果需要我可以添加配置文件。
提前致谢。
您需要确保正确发送承载身份验证
Authorization: Bearer <token>
您的令牌声明需要包含 ClaimsIdentity.UserIdClaimType
and/or ClaimsIdentity.UserNameClaimType
(老实说,不确定是哪个),用户才能被识别为已通过身份验证。实现这一点的最简单方法是使用最终调用 UserClaimsPrincipalFactory.GenerateClaimsAsync()
的 SignInManager.CreateUserPrincipalAsync()
,例如这个帮手来自我的一个项目:
public async Task<string> GetToken(ApplicationUser user, TimeSpan? expiresIn)
{
var principal = await signInManager.CreateUserPrincipalAsync(user);
if (principal == null)
return null;
var signingKey = GetSecurityKey(configuration);
var token = new JwtSecurityToken(
expires: DateTime.UtcNow + expiresIn,
claims: principal.Claims,
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
另一个选项似乎是您可以指定 IdentityOptions.ClaimsIdentity
in config to teach Identity that UserID
is the Claim Type it should use to identify your user (based on this code)。
我无法使用 Asp.net Core 生成的令牌授权访问受保护的方法。
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApplicationSettings>
(Configuration.GetSection("ApplicationSettings"));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddScoped<IRepository<Course>, GenericRepository<Course>>();
services.AddRazorPages();
// CORS - Configuration
services.AddCors(opt =>
opt.AddPolicy("CorsPolicy", policy =>
policy.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "LMS Basic API",
Description = "LMS Diamond for api",
});
//c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
//{
// Name = "Authorization",
// Type = SecuritySchemeType.ApiKey,
// Scheme = "Bearer",
// BearerFormat = "JWT",
// In = ParameterLocation.Header,
// Description = "JWT Authorization header using the Bearer scheme."
//});
//c.AddSecurityRequirement(new OpenApiSecurityRequirement
//{
// {
// new OpenApiSecurityScheme
// {
// Reference = new OpenApiReference
// {
// Type = ReferenceType.SecurityScheme,
// Id = "Bearer"
// }
// },
// new string[] {}
// }
//});
});
// JWT Auth
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
//app.UseRewriter(new RewriteOptions()
// .AddRedirectToHttpsPermanent());
app.UseCors("CorsPolicy");
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "LMS Basic API");
c.RoutePrefix = string.Empty;
});
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
登录操作时生成令牌
var tokenDescripter = new SecurityTokenDescriptor
{
Subject = new System.Security.Claims.ClaimsIdentity(new Claim[] {
new Claim("UserID", user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddSeconds(20),
SigningCredentials = new SigningCredentials(new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(applicationSettings.JWT_Secret)),
SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescripter);
var token = tokenHandler.WriteToken(securityToken);
动作
[HttpGet]
[Authorize(AuthenticationSchemes = "Bearer")]
[Route("GetUserData")]
public async Task<IActionResult> GetUserData()
{
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return BadRequest();
}
return Ok(new
{
user.Id,
user.FullName,
user.Email,
});
}
我可以在 Postman 的 HTTP headers 中添加或不添加授权,我收到一个 "Unauthorized Exception - 401"
我已经检查了一些其他的Stack post和GitHub Post,看来我的配置没问题。
如果需要我可以添加配置文件。
提前致谢。
您需要确保正确发送承载身份验证
Authorization: Bearer <token>
您的令牌声明需要包含 ClaimsIdentity.UserIdClaimType
and/or ClaimsIdentity.UserNameClaimType
(老实说,不确定是哪个),用户才能被识别为已通过身份验证。实现这一点的最简单方法是使用最终调用 UserClaimsPrincipalFactory.GenerateClaimsAsync()
的 SignInManager.CreateUserPrincipalAsync()
,例如这个帮手来自我的一个项目:
public async Task<string> GetToken(ApplicationUser user, TimeSpan? expiresIn)
{
var principal = await signInManager.CreateUserPrincipalAsync(user);
if (principal == null)
return null;
var signingKey = GetSecurityKey(configuration);
var token = new JwtSecurityToken(
expires: DateTime.UtcNow + expiresIn,
claims: principal.Claims,
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
另一个选项似乎是您可以指定 IdentityOptions.ClaimsIdentity
in config to teach Identity that UserID
is the Claim Type it should use to identify your user (based on this code)。