WebApi Authorize属性与services.AddIdentity返回404 Not Found [英] WebApi Authorize attribute with services.AddIdentity returns 404 Not Found

查看:126
本文介绍了WebApi Authorize属性与services.AddIdentity返回404 Not Found的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的WebApi项目,该项目使用 IdentityServer4.AccessTokenValidation 来验证 IdentityServer4 服务器在以下位置发布的令牌开发地址: https:// localhost:44347

I have a simple WebApi project, which uses IdentityServer4.AccessTokenValidation to validate tokens issued by an IdentityServer4 Server at development address: https://localhost:44347

我通过将以下数据发送到Identityserver获得令牌:

I get the token by sending following data to identityserver:

POST
https://localhost:44347/connect/token
client_id:x.api.client
client_secret:secret
response_type:code id_token
scope:X.api
grant_type:client_credentials

响应为:

{
    "access_token": "THETOKEN",
    "expires_in": 1209600,
    "token_type": "Bearer"
}

并将令牌发送到WebAPi

and sending the token to WebAPi

POST
http://localhost:59062/identity
Authorization:Bearer THETOKEN

我得到了想要的结果,但是,在下面的代码结果中添加了注释部分找不到404。

I get desired result, but, adding commented part of following code results 404 Not Found.

代码是:

public class Startup {

    private const string API_NAME = "X.api";

    public Startup(IConfiguration configuration) {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services) {

        string connectionString = Configuration.GetConnectionString("DefaultConnection");

        services.AddLogging(configure => configure.AddConsole());

        services.AddDbContext<MyDataContext>(options => options.UseSqlServer(connectionString));

        services.AddMvcCore()
            .AddAuthorization()
            .AddJsonFormatters()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        services.AddTransient<IUserStore<MyUser>, MyUserStore>();
        services.AddTransient<IRoleStore<MyRole>, RoleStore>();
        services.AddTransient<IPasswordHasher<MyUser>, MyHasher>();


        services.AddAuthentication("Bearer")
        .AddIdentityServerAuthentication(options => {
            options.Authority = "https://localhost:44347";
            options.RequireHttpsMetadata = false;
            options.ApiName = API_NAME;
        });


        ////This commented part brokes API
        //services.AddIdentity<MyUser, MyRole>(options => {
        //  options.Password.RequireDigit = true;
        //  options.Password.RequiredLength = 6;
        //  options.Password.RequireNonAlphanumeric = false;
        //  options.Password.RequireUppercase = false;
        //  options.Password.RequireLowercase = false;
        //  options.SignIn.RequireConfirmedEmail = false;
        //})
        //Bekaz we are not using IdentityUser as base
        //.AddUserStore<MyUserStore>()
        //.AddRoleStore<RoleStore>()
        //.AddDefaultTokenProviders();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
        if (env.IsDevelopment()) {
            app.UseDeveloperExceptionPage();
        }

        app.UseAuthentication();
        app.UseMvc();
    }
}

API就像下面的代码一样简单(身份服务器的示例之一)

the API is as simple as following piece of code(one of identity server's samples)

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;

namespace Api.Controllers {
  [Route("[controller]")]
  [Authorize]
  public class IdentityController : ControllerBase {
    [HttpGet]
    public IActionResult Get() {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }
  }
}

我使用自定义的用户类来自 IIdentity ,自定义 Role UserRole ,自定义 RoleStore 已实现 IRoleStore< MyRole> ,而自定义 UserStore 已实现 IUserStore< MyUser>,IUserPasswordStore< MyUser>

I use custom User class inherited from IIdentity, custom Role and UserRole, custom RoleStore implemented IRoleStore<MyRole>, and custom UserStore implemented IUserStore<MyUser>, IUserPasswordStore<MyUser>.

编辑,更多信息

这是我在控制台上得到的:

this is what i get on console:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/identity
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Route matched with {action = "Get", controller = "Identity"}. Executing action Api.Controllers.IdentityController.Get ()
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
[16:48:20 Information] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was challenged.

info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
      AuthenticationScheme: Identity.Application was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action Api.Controllers.IdentityController.Get () in 30.1049ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 103.2969ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/Account/Login?ReturnUrl=%2Fidentity
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 0.468ms 404

临时解决方案

有些东西具有授权系统,我最终将属性更改为我在此处建立的

there is something with authorization system, I finally changed attribute to what i founded here

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

,它起作用。但是如何以及为什么呢?我现在还没有

and it works. but how and why? I don't now yet.

此外,将 AddAuthentication 部分更改为下面的内容,如前面提到的答案所示, >有效,并且需要将(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)传递给 [Authorize]

Also, changing the AddAuthentication part to bellow, as mentioned answer suggets, Does Not works and requires the (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme) to be passed to [Authorize]

        services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddIdentityServerAuthentication(options => {
            options.Authority = "https://localhost:44347";
            options.RequireHttpsMetadata = false;

            options.ApiName = API_NAME;
        });

更改订单终于可以了。(第一个 AddIdentity 然后单击 AddAuthentication

changing order, finally works.(first AddIdentity and then AddAuthentication)

        services.AddIdentity<MyUser, MyRole>(options => {
            options.Password.RequireDigit = true;
            options.Password.RequiredLength = 6;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireLowercase = false;
            options.SignIn.RequireConfirmedEmail = false;
        })
        .AddUserStore<MyUserStore>()
        .AddRoleStore<RoleStore>();


        services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddIdentityServerAuthentication(options => {
            options.Authority = "https://localhost:44347";
            options.RequireHttpsMetadata = false;

            options.ApiName = API_NAME;
        });


推荐答案

让我尝试解释一下,于是其他一些穷人灵魂有一些更容易理解的时间:)

Let me try at explain this, so some other poor soul have some easier time understanding :)

当像上面那样添加身份验证时

When Authentications are added like above

  services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        ....

这意味着每个属性[Authorize]放在方法或控制器类的顶部,将尝试针对默认的身份验证架构(在本例中为JwtBearer)进行身份验证并且不会取消连接,以尝试与可能会导致冲突的其他架构进行身份验证被声明(如Cookie模式)。为了使AuthorizeAttribute针对cookie模式进行身份验证,必须像上面的代码中那样指定

It means that every attribute [Authorize] that is put on top of a method or a controller class, will try to authenticate against the default authentication schema (in this case the JwtBearer) AND IT WILL NOT CASCADE DOWN to try to authenticate with other schemas that might be declared (like Cookie schema). In order to make the AuthorizeAttribute authenticate against the cookie schema it has to be specified like in code above

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]

这也可以正常工作,例如,如果cookie模式是默认设置,则必须为需要JwtBearer令牌认证的方法或控制器声明JwtBearer模式以进行授权

This will work also the other way around, i.e. if cookie schema is default then the JwtBearer schema must be declared for authorization for those methods or controllers that would need JwtBearer token authentication

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

这篇关于WebApi Authorize属性与services.AddIdentity返回404 Not Found的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆