ASP.NET Core 5.0 JWT 身份验证引发 401 代码 [重复]
Posted
技术标签:
【中文标题】ASP.NET Core 5.0 JWT 身份验证引发 401 代码 [重复]【英文标题】:ASP.NET Core 5.0 JWT authentication is throws 401 code [duplicate] 【发布时间】:2021-08-24 04:15:09 【问题描述】:我有一个使用 JWT 身份验证的 ASP.NET Core 5.0 API。
我现在想要做的就是读取按钮中的标记
@html.ActionLink("Test","Oper","Home")
它是[Authorize]
标头,并根据我的标准验证它们。我不知道错过了什么,但它总是返回 HTTP 401 代码。
测试添加此代码
app.UseCors(x => x.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("https://localhost:4200"));
错误:
System.InvalidOperationException:CORS 协议不允许同时指定通配符(任何)来源和凭据。如果需要支持凭据,请通过列出各个来源来配置 CORS 策略。
连接终端的pty主机进程无响应,终端可能停止工作
这不是一个 Angular 项目。
这是Startup.cs
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.FileProviders;
using System.IO;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace JWTtokenMVC
public class Startup
public Startup(IConfiguration configuration)
Configuration = configuration;
public IConfiguration Configuration get;
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
services.AddControllersWithViews();
services.AddCors(options =>
options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials().Build());
);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
NameClaimType ="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
RoleClaimType ="http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
ValidateIssuer = true,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])
)
;
);
// 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();
else
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Test_modules")),
RequestPath = "/" + "Test_modules"
);
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(x => x.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("https://localhost:4200"));
app.UseEndpoints(endpoints =>
endpoints.MapControllerRoute(
name: "default",
pattern: "controller=Home/action=Index/id?");
);
这是HomeController.cs
- 登录获取 Jwt 令牌就可以了:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using JWTtokenMVC.Models;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.Extensions.Configuration;
using JWTtokenMVC.Models.Test;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
namespace JWTtokenMVC.Controllers
public class HomeController : Controller
private IConfiguration _config;
public HomeController(IConfiguration config)
_config = config;
public IActionResult Index()
return View();
public IActionResult Privacy()
return View();
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
return View(new ErrorViewModel RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );
private string GenerateJSONWebToken(UserPaul userinfo)
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
new Claim(JwtRegisteredClaimNames.Sub,userinfo.Username),
new Claim(JwtRegisteredClaimNames.Email,userinfo.Email),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
;
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(10),
signingCredentials: credentials
);
var encodetoken = new JwtSecurityTokenHandler().WriteToken(token);
var cookieOptions = new CookieOptions();
//cookieOptions.Expires = DateTimeOffset.UtcNow.AddHours(12);//you can set this to a suitable timeframe for your situation
cookieOptions.HttpOnly = true;
cookieOptions.Expires = DateTime.Now.AddMinutes(1);
//cookieOptions.Domain = Request.Host.Value;
cookieOptions.Path = "/";
Response.Cookies.Append("jwt", encodetoken, cookieOptions);
return encodetoken;
[HttpPost]
public IActionResult Login()
string AccountNumber="TestUser";
JWTtokenMVC.Models.TestContext userQuery = new JWTtokenMVC.Models.TestContext();
var query = userQuery.Testxxxx.Where(N => N.UserId ==AccountNumber).FirstOrDefault();
IActionResult response = Unauthorized();
if (query != null)
var tokenStr = GenerateJSONWebToken(query);
response = Ok(new token = tokenStr );
return response;
[Authorize]
[HttpGet("Home/Oper")]
public IActionResult Oper()
var authenticationCookieName = "jwt";
var cookie = HttpContext.Request.Cookies[authenticationCookieName];
List<Test_SHOW> sHOWs = new List<Test_SHOW>();
JWTtokenMVC.Models.Test.TestContext userQuery= new JWTtokenMVC.Models.Test.TestContext();
var query = userQuery.Test.Select(T => new Test_SHOW
number= T.number,
name= T.name,
mail= T.mail
).OrderBy(o => o.Iid);
sHOWs.AddRange(query);
return View("Views/Home/Oper.cshtml", sHOWs);
这是Test.cshtml
:
@
ViewBag.Title = "Home Page";
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions
public string GetAntiXsrfRequestToken()
return Xsrf.GetAndStoreTokens(Context).RequestToken;
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">
<form method="post" asp-antiforgery="false">
<!--form -->
<div>
<span style="color:red">@ViewBag.Msg</span>
</div>
<div class="col-md-4 select-outline">
</div>
<button type="button" class="btn btn-light">@Html.ActionLink("Test","Oper","Home")</button>
<button type="button" class="btn btn-light">@Html.ActionLink("TestLogin","Login","Home")</button>
</form>
最后是Oper.cshtml
:
@using JWTtokenMVC.Models.Test
@model List<Test_SHOW>
@
ViewBag.Title = "test";
<h2>Test List</h2>
<table class="table table-hover">
<tr>
<th>
number
</th>
<th>
name
</th>
<th>
mail
</th>
</tr>
@foreach (var item in Model)
<tr>
<td>
@Html.DisplayFor(modelItem => item.number)
</td>
<td>
<span class='text-danger'>@Html.DisplayFor(modelItem => item.name)</span>
</td>
<td>
<span class='text-danger'>@Html.DisplayFor(modelItem => item.mail)</span>
</td>
</tr>
</table>
这是我的appsettings.json
文件:
"Logging":
"LogLevel":
"Default": "TestInformation",
"Microsoft": "TestWarning",
"Microsoft.Hosting.Lifetime": "TestInformation"
,
"AllowedHosts": "*",
"Jwt":
"Key": "TestProdigy",
"Issuer": "Test.mail.com"
【问题讨论】:
对不起,已经更新了代码 在 appsettings.json 中更改你的 Jwt 键,我认为应该是 16 个字符的长度。 是的,new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
SecurityAlgorithms.HmacSha256
需要 16 个字符长 .. 也遇到了这个问题并在 idx10603 SO question 上进行了审核
试试app.UseCors("CorsPolicy");
i ref [idx10603 SO question](***.com/questions/47279947/…) 已经更新了代码,但要读取按钮@Html.ActionLink("Test","Oper","Home") 中的标记和它是 [Authorize] 标头并根据我的标准验证它们。我不知道错过了什么,但它总是返回 HTTP 401 代码。
【参考方案1】:
@Patriom Sarkar 的回答解决了您的 CORS 问题/错误
关于您的 401 Unauthorized Responses
这些可能与 CORS 无关。
您在这里遇到的问题是您已将 JwtBearer JSON Web 令牌配置为出现在对您的 Authorize
端点的请求中。默认情况下,它将使用您的授权请求标头中存在的 Bearer 令牌。
这意味着,为了导航/调用Oper()
,您需要确保“授权:承载token”存在且具有有效令牌(作为请求标头)。
目前,在您的Login
处理中,您正在生成令牌并执行Set-Cookie
,以便用户代理/客户端使用令牌作为值创建“jwt”cookie;但是,用户代理不会自动将该 jwt cookie 作为 Authorization: Bearer Token 添加到后续请求的标头中。因此,Authorize
属性端点上的 JwtBearer
配置将无效。
另外值得注意的是,在 SPA 框架中支持并正常设置 Xhr 或 Fetch 操作中的标头(包括 Cookie 存储的 jwt_tokens)。但是,您在这里不是在执行 Xhr 或 Fetch 请求,而是在执行 html 表单发布工作流/机制 - 导航页面/视图。在这方面,无法在客户端设置授权标头(AFAIK)。
要在此处支持页面/视图导航,您需要在服务器端实施一个解决方案,该解决方案使用传递的 jwt
cookie 设置令牌。
@Kirk Larkin 在In ASP.NET Core read JWT token from Cookie instead of Headers 中介绍了该解决方案
.AddJwtBearer(options =>
options.Events = new JwtBearerEvents
OnMessageReceived = context =>
context.Token = context.Request.Cookies["jwt"];
return Task.CompletedTask;
;
);
另外
context.Token
始终为 null
或在此范围内为空。此声明和分配不会发生预处理或后处理。如果您打算支持 Authorization Header 和 Cookie,则应在此 OnMessageReceived
分配的委托中实现该条件。
您可以查看JwtBearerHandler (aspnetcore 5.0) on GitHub 的默认处理方式。
再次感谢 @Kirk Larkin 在对链接问题的回复评论中提供此附加信息。
【讨论】:
@Brett Caswell
answer 非常感谢解决我的问题【参考方案2】:
正如@Yinkiu 提到的。您必须使用app.UseCors("CorsPolicy")
,因为它不是您已经提到的角度项目。安装 NuGet 包
Microsoft.AspNetCore.Cors
我已经回答了你的一个与此相关的问题。这是另一个过程。你实际上不能同时使用AllowAnyOrigin()
和AllowCredentials()
。但是如果你想要AllowCredentials()
和AllowAnyOrigin()
一起使用这个SetIsOriginAllowed(Func<string,bool> predicate)
About IsOriginAllowed
services.AddCors(options =>
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
options.AddPolicy("signalr",
builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed(hostName => true));
);
【讨论】:
以上是关于ASP.NET Core 5.0 JWT 身份验证引发 401 代码 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
JWT 身份验证 ASP.NET Core MVC 应用程序