WebApi Authorize属性与services.AddIdentity返回404 Not Found [英] WebApi Authorize attribute with services.AddIdentity returns 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屋!