ASP.NET Core 3.1 MVC JWT 登录返回 401

Posted

技术标签:

【中文标题】ASP.NET Core 3.1 MVC JWT 登录返回 401【英文标题】:ASP.NET Core 3.1 MVC JWT Login return 401 【发布时间】:2021-11-01 15:18:18 【问题描述】:

我有一个问题,jwt 认证返回 401 错误。 令牌已创建但总是返回 401 错误。

我使用了分层架构。我在 startup.cs 上尝试了很多东西。 JWT 和 startup.cs 代码在下面。如果您想查看其他代码,将会更新。

JwtHelper 代码:

 public class JwtHelper : ITokenHelper
    
        public IConfiguration Configuration  get; 
        private TokenOptions _tokenOptions;
        private DateTime _accessTokenExpiration;
        public JwtHelper(IConfiguration configuration)
        
            Configuration = configuration;
            _tokenOptions = Configuration.GetSection("TokenOptions").Get<TokenOptions>();

        
        public AccessToken CreateToken(User user, List<OperationClaim> operationClaims)
        
            _accessTokenExpiration = DateTime.Now.AddMinutes(_tokenOptions.AccessTokenExpiration);
            var securityKey = SecurityKeyHelper.CreateSecurityKey(_tokenOptions.SecurityKey);
            var signingCredentials = SigningCredentialsHelper.CreateSigningCredentials(securityKey);
            var jwt = CreateJwtSecurityToken(_tokenOptions, user, signingCredentials, operationClaims);
            var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            var token = jwtSecurityTokenHandler.WriteToken(jwt);

            return new AccessToken
            
                Token = token,
                Expiration = _accessTokenExpiration
            ;

        

        public JwtSecurityToken CreateJwtSecurityToken(TokenOptions tokenOptions, User user,
            SigningCredentials signingCredentials, List<OperationClaim> operationClaims)
        
            var jwt = new JwtSecurityToken(
                issuer: tokenOptions.Issuer,
                audience: tokenOptions.Audience,
                expires: _accessTokenExpiration,
                notBefore: DateTime.Now,
                claims: SetClaims(user, operationClaims),
                signingCredentials: signingCredentials
            );
            return jwt;
        

        private IEnumerable<Claim> SetClaims(User user, List<OperationClaim> operationClaims)
        
            var claims = new List<Claim>();
            claims.AddNameIdentifier(user.id.ToString());
            claims.AddEmail(user.Email);
            claims.AddName($"user.FirstName user.LastName");
            claims.AddRoles(operationClaims.Select(c => c.name).ToArray());

            return claims;
        
    

Statup.cs

  public void ConfigureServices(IServiceCollection services)
        
            services.AddCors();
            services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
            services.AddControllersWithViews();
            services.AddRazorPages();
            var tokenOptions = Configuration.GetSection("TokenOptions").Get<TokenOptions>();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                
                    options.TokenValidationParameters = new TokenValidationParameters
                    
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidIssuer = tokenOptions.Issuer,
                        ValidAudience = tokenOptions.Audience,
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey)
                    ;
                );


            services.AddControllersWithViews();
            services.AddDependencyResolvers(new ICoreModule[] 
                new CoreModule()
            );
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(o => 
        o.LoginPath = "/Auth/Login";
    );
        

        // 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.UseCors(builder => builder.WithOrigins("https://localhost:44378").AllowAnyHeader());
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseAuthentication();
            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller=Customer/action=Index/id?");
            );
            app.UseStatusCodePages();
        

我已经搜索了 1 周,但没有找到。

【问题讨论】:

查看编译器警告。 app.UseAuthentication 需要之前 app.UseAuthorization。这只是一个问题,可能还有更多。 @CamiloTerevinto 不幸的是它没有用。 :( 【参考方案1】:

当你注册 JwtToken 处理程序后,这个

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(o => 
        o.LoginPath = "/Auth/Login";

将您的默认身份验证方案设为 CookieAuthenticationDefaults.AuthenticationScheme,它使用 cookie 作为验证。

代码应该是

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme, opts => 

    opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
)
    .AddJwtBearer(options =>
    
        options.TokenValidationParameters = new TokenValidationParameters
        
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidIssuer = tokenOptions.Issuer,
            ValidAudience = tokenOptions.Audience,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey)
        ;
    )
    .AddCookie(o => 
        o.LoginPath = "/Auth/Login";
    );;

正如@Camilo Terevinto 所说,app.UseAuthentication 必须在 app.UseAuthorization 之前。

【讨论】:

视图重定向与身份验证完全不同的概念,请随意应用您自己的逻辑

以上是关于ASP.NET Core 3.1 MVC JWT 登录返回 401的主要内容,如果未能解决你的问题,请参考以下文章

使用两个 JWT 身份验证方案,ASP.NET Core 3.1

ASP.Net Core - 使用 WebAPI 和 MVC 前端的 JWT 身份验证不起作用

JWT 身份验证 ASP.NET Core MVC 应用程序

使用 ADFS 的 JWT Bearer 身份验证将 ASP.NET Framework 迁移到 ASP.NET Core 3.1

将 JWT 自动加载到 User.Identity (ASP.NET Core 3.1)

JWT 不记名令牌不适用于 ASP.Net Core 3.1 + Identity Server 4