且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

从MVC迁移到ASP.NET Core 3.1中的端点路由时,AuthorizeAttribute的角色不起作用

更新时间:2023-02-15 12:37:48

事实证明,因为我们使用的是app.Use()中间件来填充数据库中的用户角色,因此需要在UseAuthorisation之前调用它在执行授权之前已加载角色.(就像@CamiloTerevinto的评论一样)

  app.UseSession();app.UseRouting();app.UseAuthentication();//将用户角色添加为他的身份声明,以便出于身份验证目的进行选择app.Use((context,next)=>{...}//将授权中间件设置为仅在加载用户角色后才运行.app.UseAuthorization();app.UseResponseCompression(); 

I'm trying to upgrade my project from .UseMVC (asp.net core 2.2 compat style) to .UseEndpoint Routing and I'm getting re-directed to my suthentication failed page for all my requests. It has to do with the Claims - If I remove the role part of [Authorize(Roles = "Admin")] to simply [Authorize] then it works. It seems that it isn't picking up the claims that are assigned to the user.

It seems to be a very similar issue as AuthorizeAttribute not working with Endpoint Routing in ASP.NET Core 3.1

The following paragraph is an excerpt from the linked post but modified to reflect my version of the issue

Everything worked fine in 2.2, but after migrating to 3.1 and enabling Endpoint Routing, this controller began to refuse requests to any endpoint when [Authorize(Roles = "Admin")] attribute is present. When I remove "Roles =" part and look at User.Claims, I can see that it does have the required claims/roles. This happens only if Endpoint Routing is enabled, in case of using UseMvc everything works properly. What's wrong with Authorization in Endpoint Routing mode?

Excerpt from Startup.cs

 app.UseSession();
    
 app.UseRouting();
    
 app.UseAuthentication();
 app.UseAuthorization();
 app.UseResponseCompression();
 //Add the users Roles as claims to his identity so that it is picked up for authentication purposes
 app.Use((context, next) =>
 {
     var userId = context.User.Identity.Name;
     if (userId == null)
     {
         return next();
     }
    
     ...
        
     var roles = resourceDataAccess.GetRolesForUser(userId);
     if (roles != null)
     {
         var claims = roles.Select(role => new Claim(ClaimTypes.Role, role.RoleEnum.ToString())).ToList();
    
         var appIdentity = new ClaimsIdentity(claims);
         context.User.AddIdentity(appIdentity);
     }
    
     return next();
 });
 app.UseEndpoints(endpoints =>
 {
     endpoints.MapHub<AppHub>("api/apphub");
     endpoints.MapControllerRoute("default", "api/{controller=Account}/{action=SignIn}/{id?}");
     endpoints.MapControllerRoute("catch-all", "api/{*url}",
             new {controller = "Utility", action = "NotFoundPage"});
 });

It turns out since we were using app.Use() middleware to fill in the user's roles from the DB, it needed to be called before UseAuthorisation so that the roles were loaded before authorisation was performed. (Like @CamiloTerevinto's comment)

 app.UseSession();
    
 app.UseRouting();
    
 app.UseAuthentication();
 //Add the users Roles as claims to his identity so that it is picked up for authentication purposes
 app.Use((context, next) =>
 {
   ...
 }
 //Setup the authorisation middleware to run only after we have loaded the users roles.
 app.UseAuthorization();
 app.UseResponseCompression();