首页 > 解决方案 > 来自邮递员的 JWT 令牌从不使用 Authorize 属性访问控制器

问题描述

试图了解 JWT 如何为 asp.net 核心应用程序工作。我使用 ASP.NET MVC Core 应用程序模板。 在此处输入图像描述

我的 StartUp.cs 包含 JWT Token 的配置:

 public class Startup
{
     // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };

            //options.EventsType = typeof(AuthenticateCustomEvent);
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        // In production, the React files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/build";
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseAuthentication();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/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.UseSpaStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action=Index}/{id?}");
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseReactDevelopmentServer(npmScript: "start");
            }
        });
    }
}

我的登录控制器包含在成功验证用户时返回令牌的代码,这将返回一个令牌,如下所示

在此处输入图像描述

一旦我收到令牌,我就使用来自 PostMan 的承载令牌应用了 [Authorize] 属性来调用控制器,控制器永远不会被击中?我错过了什么吗?

标签: asp.net-web-apijwtasp.net-core-2.0bearer-token

解决方案


我下面的解决方案有点不同,但是这个解决方案将帮助您处理自定义身份验证实现,您可以为不同类型的用户实现不同类型的身份验证。您需要在您的 API 项目下创建一个 AuthorizationRequiredAttribute 类,该类将继承ActionFilterAttribute类来过滤每个 API 请求。您可以过滤所有 HTTP 方法(GET、POST、PUT、DELETE...等),并且可以为特定的 HTTP 方法实现自己的授权逻辑。

ActionFilterAttribute.cs

using BillSyatemCore.Common.Constants;
using BillSyatemCore.Services.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;

namespace BillSyatemCore.Handlers
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class AuthorizationRequiredAttribute : ActionFilterAttribute
    {
        private IConfiguration _config;
        public AuthorizationRequiredAttribute(IConfiguration config)
        {
            _config = config;
        }
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            try
            {
                if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
                {
                    var handler = new JwtSecurityTokenHandler();
                    var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
                        as JwtSecurityToken;
                    var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
                    if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
                    {
                        if (expireDate < DateTime.Now)
                        {
                            context.Result = new UnauthorizedResult();
                        }
                    }
                    else
                    {

                        //You may filter post,put,delete etc request here.  
                    }
                }
                else
                {
                    context.Result = new NotFoundResult();
                }
            }
            catch (Exception ex)
            {
                context.Result = new BadRequestResult();
            }
            base.OnActionExecuting(context);
        }
    }
}

启动.cs

public void ConfigureServices(IServiceCollection services)
{
    //JWT
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
        };
    });
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
        .Build());
    });

}

控制器.cs

using BillSyatemCore.Models.Authentication;
using BillSystemCore.Transporter;
using Microsoft.AspNetCore.Mvc;

namespace TestProject.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]")]
    public class UserTypeController : Controller
    {
        private readonly IAuthTransporter _authTransporter;
        public UserTypeController(IAuthTransporter authTransporter)
        {
            _authTransporter = authTransporter;
        }
        [HttpPost("save"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
        public IActionResult Save([FromBody] UserType userType)
        {
            return Ok(_authTransporter.UserTypeServices.Save(userType));
        }
    }
}

推荐阅读