问题描述
我有一个使用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协议不允许同时指定通配符(Any)来源和凭据。如果需要支持凭据,请通过列出各个来源来配置CORS策略。
与终端的PTY主机进程的连接没有响应,终端可能会停止工作
这不是角度项目。
这是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
-登录GET 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"
}
}
推荐答案
@Patriom Sarkar的回答解决了您的CORS问题/错误
关于您的401个未经授权的回复
这些可能与CORS无关。
您在这里遇到的问题是,您已经将JwtBeeller JSON Web令牌配置为出现在对Authorize
端点的请求中。默认情况下,它将使用您的授权请求标头中存在的不记名令牌。
这意味着,为了导航/调用Oper()
,您需要确保";Authorization:Beader{Token}&Quot;存在有效的令牌(作为请求标头)。
Login
处理中,您正在生成令牌并执行Set-Cookie
,以便用户代理/客户端使用该令牌作为值创建‘JWT’cookie;但是,用户代理不会自动将该JWT cookie作为Authorization:Beader Token添加到后续请求的头部。因此JwtBearer
属性终结点上的JwtBearer
配置将无效。还值得注意的是,在Xhr或FETCH操作中设置头部在SPA框架中是受支持和正常的(包括Cookie存储的JWT_TOKEN)。然而,在这里您不是在执行Xhr或FETCH请求,而是在执行html表单POST工作流/机械导航页面/视图。在这方面,(AFAIK)无法设置Authorization Header客户端。
若要在此处支持页面/视图导航,您需要在服务器端实现一个使用传递的jwt
Cookie设置令牌的解决方案。
该解决方案在In ASP.NET Core read JWT token from Cookie instead of Headers中由@Kirk Larkin
介绍 .AddJwtBearer(options => {
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["jwt"];
return Task.CompletedTask;
}
};
});
其他
context.Token
在此作用域中始终为null
或为空。此声明和赋值不会进行任何预处理或后处理。如果您打算支持授权标头和Cookie,则应在此OnMessageReceived
分配委托中实现条件。
您可以查看JwtBearerHandler (aspnetcore 5.0) on GitHub的默认处理。
再次感谢@Kirk Larkin在对链接问题的回复评论中提供此附加信息。
这篇关于ASP.NET Core 5.0 JWT身份验证抛出401代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!