不记名令牌出现 401 错误 - asp.net core 3.1
Posted
技术标签:
【中文标题】不记名令牌出现 401 错误 - asp.net core 3.1【英文标题】:401 error with bearer token - asp.net core 3.1 【发布时间】:2020-11-16 18:52:29 【问题描述】:我无法使用由 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 标头中添加或不添加自动化,我收到 "Unauthorized Exception - 401"
我已经查看了其他一些 Stack 帖子和 GitHub 帖子,看来我的配置还可以。
如果需要我可以添加配置文件。
提前致谢。
【问题讨论】:
愚蠢的问题,您的令牌将在 20 秒后过期。你确定那不是问题?你能增加那个时间再试一次吗? 是的,改了还是一样的错误 【参考方案1】:您的令牌声明需要包含ClaimsIdentity.UserIdClaimType
和/或ClaimsIdentity.UserNameClaimType
(不确定是哪个,老实说),才能将用户识别为经过身份验证。实现这一点的最简单方法是使用SignInManager.CreateUserPrincipalAsync()
,它最终调用UserClaimsPrincipalFactory.GenerateClaimsAsync()
,例如我的一个项目中的这个助手:
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
来教导 Identity UserID
是它应该用来识别您的用户的声明类型(基于 this code)。
【讨论】:
【参考方案2】:您需要确保正确发送不记名身份验证
Authorization: Bearer <token>
查看示例 - Add Bearer Token to an API request
【讨论】:
当您使用类型为不记名令牌的授权时,无需在 Postman 中为您的令牌添加“不记名”。您必须手动添加授权标头。以上是关于不记名令牌出现 401 错误 - asp.net core 3.1的主要内容,如果未能解决你的问题,请参考以下文章
如何诊断尝试在 c# .NET Core 中获取 OAuth2 不记名令牌的 401 错误?
即使在 asp.net core 5.0 中提供了不记名令牌,也会返回 401 [关闭]
JWT不记名令牌授权不起作用asp net core web api