【问题标题】:ASP.NET Core 5.0 JWT authentication is always throws HTTP 401 codeASP.NET Core 5.0 JWT 身份验证总是抛出 HTTP 401 代码
【发布时间】:2021-08-22 12:38:43
【问题描述】:

我想在 ASP.NET Core 中实现基于 JWT 的安全性。目前,我想做的就是读取按钮 @Html.ActionLink("Test","Oper","Home") 中的令牌,授权标题并根据我的标准验证它们。我不知道错过了什么,但它总是返回 HTTP 401 代码。

文件HomeController.cs

        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.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);
 
        }

这是 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(), "node_modules")),
                RequestPath = "/" + "node_modules"
            });
            app.UseCookiePolicy();

            app.UseRouting();
            app.UseAuthentication();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Startup.cs 图片

Startup.cs 添加 UseAuthentication

【问题讨论】:

  • 请不要将代码包含为图像。用文本替换您的启动图像。
  • 请把代码中使用的设置值也加进去

标签: c# asp.net-core jwt asp.net-core-mvc


【解决方案1】:

我不确定这与原始问题的相关性如何,但我想我会插话。

在这个问题上挣扎了一段时间后,我最终添加了@Brett Caswell 所说的内容来解决我的问题。

services.AddAuthentication(options => {
    //add configs
})
.AddJwtBearer(x => {
    //add more configs
    x.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    context.Token = context.Request.Headers["Authorization"];
                    return Task.CompletedTask;
                },
            };
})

这是在意识到我的 JwtAuth 方案正在提供令牌之后,但是一旦将令牌送回进行验证,它就没有在我为我的项目设置的启动或配置中的任何地方命中。将此添加到您的 .AddJwtBearer() 块中,您应该会很好。

【讨论】:

    【解决方案2】:

    @Patriom Sarkar 的回答解决了您的 CORS 问题/错误

    关于您的 401 Unauthorized Responses

    这些可能与 CORS 无关。

    您在这里遇到的问题是您已将 JwtBearer JSON Web 令牌配置为出现在对您的 Authorize 端点的请求中。默认情况下,它将使用您的授权请求标头中存在的 Bearer 令牌。

    这意味着,为了导航/调用Oper(),您需要确保“Authorization: Bearer {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 或为空。此声明和分配不会发生预处理或后处理。如果您打算支持授权标头和 Cookie,则应在此 OnMessageReceived 分配的委托中实现该条件。

    您可以查看JwtBearerHandler (aspnetcore 5.0) on GitHub 的默认处理方式。

    再次感谢 @Kirk Larkin 在对链接问题的回复评论中提供此附加信息。

    注意

    这个答案最初是在一个重复的问题上提供的:ASP.NET Core 5.0 JWT authentication is throws 401 code

    【讨论】:

    • @Brett Caswell 很抱歉一开始没有把我的问题表达清楚。这个问题已经修改了很多次,所以我开了一个新问题
    【解决方案3】:

    所以我假设您正在尝试使用 Angular 项目的 asp.net 核心。我认为您错过了将客户端 URL 添加到您的 .net 核心项目。 AddCorson 对 IServiceCollection 的扩展调用只是注册了所有必需的服务,但它不会将 Cors 中间件添加到 HTTP 请求管道中。所以在您的配置方法中添加此代码 app.UseCors(x =&gt; x.AllowAnyHeader().AllowAnyMethod().WithOrigins("https://localhost:4200"));。我认为它可以解决您的问题。

    
     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    //clarify code
                  
                }
                else{  
    
                   //clarify code    
    
                }
                
    
                app.UseHttpsRedirection();
    
                app.UseRouting();
    
                app.UseCors(x => 
      x.AllowAnyHeader().AllowAnyMethod().WithOrigins("https://localhost:4200")); //your  client side URL.you are missing this unfortunately
    
                app.UseAuthentication();
    
                app.UseAuthorization();
    
               //clarify code
            }
    
    

    更新

    安装Microsoft.AspNetCore.Cors

    只需删除 AllowCredentials() 即可解决您的问题。

    【讨论】:

    • 添加代码错误:CORS 协议不允许同时指定通配符(任何)来源和凭据。如果需要凭据,则通过列出各个来源来配置 CORS 策略
    • 错误:连接终端的pty主机进程无响应,终端可能停止工作。
    • 我了解您选择了 VS 代码来构建您的项目。我更新的答案是解决您的第一个问题。但您的第二个问题是您的 IDE(VS Code)。我会推荐你​​这个链接来解决你的第二个问题:-github.com/microsoft/vscode/issues/117956
    • @Pritom Sarkar answer 非常感谢我的 CORS 问题
    • @Paul 很高兴知道 :) 顺便说一句,这是与 cors 相关的问题,所以请点击RIGHT 图标接受我的回答。
    猜你喜欢
    • 2021-08-24
    • 2020-09-10
    • 2023-04-04
    • 1970-01-01
    • 2021-10-14
    • 2019-04-19
    • 2019-09-06
    • 2021-04-20
    • 1970-01-01
    相关资源
    最近更新 更多