为啥我的未经授权的控制器不返回 401 ASP.Net Core?

Posted

技术标签:

【中文标题】为啥我的未经授权的控制器不返回 401 ASP.Net Core?【英文标题】:Why don't my unauthorized controllers return 401 ASP.Net Core?为什么我的未经授权的控制器不返回 401 ASP.Net Core? 【发布时间】:2019-12-17 00:59:48 【问题描述】:

我正在使用 Visual Studio 代码,并且正在为 RestAPI 使用 dot net core 框架。当我访问具有“授权”属性的控制器时,它应该返回一个 401 请求,但它不会在邮递员中返回任何内容。只是一个空白。

我认为它应该来自我的启动代码。

我将在启动文件中分享我的配置方法。

非常感谢您的帮助。如果您可以在互联网上找到解决方案,请分享它(我已经在寻找但是......也许我没有输入正确的关键字。)

公共类启动 公共启动(IConfiguration 配置) 配置=配置;

    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)
    
        ConfigureContext(services);

        services.AddCors();
        services.AddAutoMapper(typeof(Startup));

        // configure strongly typed settings objects
        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);

        // configure jwt authentication
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        services.AddAuthentication(x =>
        
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        )
        .AddJwtBearer(x =>
        
            x.Events = new JwtBearerEvents
            
                OnTokenValidated = context =>
                
                    var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
                    var userId = int.Parse(context.Principal.Identity.Name);
                    var user = userService.GetById(userId);
                    if (user == null)
                    
                        // return unauthorized if user no longer exists
                        context.Fail("Unauthorized");
                    
                    return Task.CompletedTask;
                
            ;
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            ;
        );

        // Register the Swagger generator, defining 1 or more Swagger documents
        services.AddSwaggerGen(c =>
        
            c.SwaggerDoc("v1", new OpenApiInfo
            
                Title = "dotnetcore-api-core",
                Version = "v1"
            );
        );
        services.AddScoped<IUserService, UserService>();
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    

    // 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();
        app.UseMvc();
        app.UseStaticFiles();
        app.UseHttpsRedirection();
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        
        else
        
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();
        // Security JWT
        app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

        // Enable middleware to serve swagger-ui (html, JS, CSS, etc.),
        // specifying the Swagger JSON endpoint.
        app.UseSwaggerUI(c =>
        
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "dotnetcore-api-core V1");
        );
    

    public void ConfigureContext(IServiceCollection services)
    
        // Database injection
        services.AddDbContext<UserContext>(options =>
            options.Usemysql(Configuration.GetConnectionString("AppDatabase")));
    

我的控制器未返回 401 未授权:

    [Authorize]
    [Route("api/users")]
    [ApiController]
    public class UserController : ControllerBase
    
        private readonly IUserService _userService;
        private IMapper _mapper;

        public UserController(
            IUserService userService,
            IMapper mapper)
        
            _userService = userService;   
            _mapper = mapper;
        

        [HttpGet]
        public async Task<ActionResult<IEnumerable<User>>> GetUsers()
        
            IEnumerable<User> users = await _userService.GetAll();

            if(users == null)
            
                return NotFound();
            

            return Ok(users);
        

我按照本教程进行操作 -> https://jasonwatmore.com/post/2018/08/14/aspnet-core-21-jwt-authentication-tutorial-with-example-api

邮递员中的示例图像:Image example of empty body postman

【问题讨论】:

如果不返回401,返回什么? 显示控制器结构 你使用什么认证方案?你能告诉我们 ConfigureServices 方法吗? 大家好,我将编辑我的代码,向您展示的不仅仅是摘要。 我相信它正在返回 401,但正文是空的。因此,您认为您会在正文中看到 401,但您不会。请张贴 Postman 应用的截图,在你调用这个返回“nothing”的 webapi 之后 【参考方案1】:

我认为你的问题是一样的。您可以添加如下几行代码(在 Startup.cs 文件中):

选项 1:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    app.UseCors(pol => pol.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    app.UseAuthentication();

    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();

    app.UseStatusCodePages(async context =>
    
        if (context.HttpContext.Request.Path.StartsWithSegments("/api"))
        
            if (!context.HttpContext.Response.ContentLength.HasValue || context.HttpContext.Response.ContentLength == 0)
            
                // You can change ContentType as json serialize
                context.HttpContext.Response.ContentType = "text/plain";
                await context.HttpContext.Response.WriteAsync($"Status Code: context.HttpContext.Response.StatusCode");
            
        
        else
        
            // You can ignore redirect
            context.HttpContext.Response.Redirect($"/error?code=context.HttpContext.Response.StatusCode");
        
    );

    app.UseMvc();

选项 2

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    if (env.IsDevelopment())
    
       app.UseDeveloperExceptionPage();
    

    app.UseExceptionHandler("/api/errors/500");
    app.UseStatusCodePagesWithReExecute("/api/errors/0");
    // or app.UseStatusCodePagesWithRedirects("~/api/errors/0");

    app.UseRouting();

    ...

然后,像这样创建 ErrorController:

[ApiController]
[Route("api/errors")]
public class ErrorController : Controller

    [HttpGet("code")]
    public async Task<IActionResult> Get(int code)
    
        return await Task.Run(() =>
        
            return StatusCode(code, new ProblemDetails()
            
                Detail = "See the errors property for details.",
                Instance = HttpContext.Request.Path,
                Status = code,
                Title = ((HttpStatusCode)code).ToString(),
                Type = "https://my.api.com/response"
            );
        );
    

我希望这会有所帮助。

【讨论】:

【参考方案2】:

尝试将此行移到 Configure 方法的顶部:

app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

例如:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    app.UseAuthentication();
    app.UseMvc();

    // the rest of you code here

【讨论】:

您好!感谢您的评论,但没有奏效。我仍然没有在邮递员中显示任何错误的请求【参考方案3】:

您的电话正在返回 401。它在邮递员中清晰可见。正文当然是空的,但是如果您在正确的站点上看起来更高一点(与正文、cookie、标题选项卡在同一行),您会看到状态行,上面写着 401 Unauthorized。它还会向您显示此响应花费了多长时间以及响应的大小。

【讨论】:

当然但是...我想要一个完整的身体。当我使用客户端(如 Angular)时,它必须返回一个用于捕获数据的主体,对吗? 您的问题是,如果您未经授权,为什么不会收到 401 错误。您收到此错误,因此已解决。检查如何添加额外数据检查***.com/questions/48934675/… 好的,谢谢您的回复。我知道我的问题可能不清楚。对不起,我的英语肯定很差,我不能很好地表达自己。问题是,它只是在浏览器中返回状态码。不是身体,所以我无法捕捉到错误。您共享的链接无法解决问题,因为我不想创建自定义 Authorize 方法。我无法使用 Dot Net Core Framework 中包含的授权工具。 你没有发现没有body的错误?你有它说未经授权的状态。所以这是你的错误 好吧,我明白了...最后一个问题:即使 api deos 没有返回正文,我能否知道我是否在我的应用中未经授权?

以上是关于为啥我的未经授权的控制器不返回 401 ASP.Net Core?的主要内容,如果未能解决你的问题,请参考以下文章

未经授权的 webapi 调用返回登录页面而不是 401

为啥我在 Asp.Net CORE 中使用 JWT 获得 401 未经授权?

React - 带有标头的 ajax GET 请求仍返回 401(未经授权)

Spring Security 测试返回 401(未经授权)

Django Tastypie 总是返回 401 未经授权

春季启动返回 401-未经授权,即使我允许它