2

我想在這裏圍繞幾個概念我的頭,但我不希望這個問題太寬泛 - 基本上我們要做的就是使用角色聲明作爲權限來鎖定下來我們的API,但我發現access_token變得太大了。OpenIdConnect access_token大小和訪問聲明服務器端

我們在服務器端使用OpenIddict和ASP.NET Identity 3。我們已經實現了默認的AspNetRoleClaims表來存儲每個角色的聲明 - 將它們用作權限。

我們使用自定義策略基於聲明的授權鎖定我們的API端點如下所示:

Custom Policy Based Authorization

我發現的主要問題是,我們包含我們的要求是的access_token變得非常大。我們試圖使ClaimType和Value在數據庫中非常小,以使索賠佔用空間更小。我們有一個基本的CRUD類型權限方案,因此對於我們的SPA客戶端應用程序中的每個「模塊」或屏幕,都有4個權限。我們添加到我們的應用程序中的模塊越多,access_token中的聲明越多,我們的Authorization Bearer標頭越來越大。我擔心隨着應用程序的增長,這種變化不會很大。

所以索賠嵌入和的access_token時,我打我的端點被鎖定,像這樣的自定義策略...

[Authorize(Policy="MyModuleCanRead")] 
[HttpGet] 
public IEnumerable<MyViewModel> Get() 

然後我就可以訪問我的ASP.NET用戶身份和用戶。在AuthorizationHandler中聲明。

對不起,如果這是一個明顯的問題 - 但我想知道 - 爲了讓基於自定義策略的授權工作 - 它是否絕對要求聲明在ID_token或access_token中以便調用處理程序?

如果我從access_token中刪除了聲明,那麼我的AuthorizationHandler代碼不會受到影響,並且我無法訪問使用自定義策略鎖定的端點。

我想知道是否可以使用自定義聲明策略,但具有檢查授權處理程序中的聲明的實際代碼,以便聲明不與每個HTTP請求一起傳遞,但是從服務器端獲取授權cookie或數據庫。

* UPDATE *

Pintpoint的使用授權處理與如何從實現正是我一直在尋找的cookie刪除其他角色的權利要求的註釋一起回答。

如果這有助於其他人 - 這裏是覆蓋UserClaimsPrincipalFactory並阻止角色聲明寫入cookie的代碼。 (我有很多角色的權利要求的權限和保存cookie和請求頭中變得太大)

public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole> 
{ 
    public AppClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor) 
    { 
    } 
    public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user) 
    { 
     if (user == null) 
     { 
      throw new ArgumentNullException(nameof(user)); 
     } 
     var userId = await UserManager.GetUserIdAsync(user); 
     var userName = await UserManager.GetUserNameAsync(user); 
     var id = new ClaimsIdentity(Options.Cookies.ApplicationCookieAuthenticationScheme, 
      Options.ClaimsIdentity.UserNameClaimType, 
      Options.ClaimsIdentity.RoleClaimType); 
     id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); 
     id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName)); 
     if (UserManager.SupportsUserSecurityStamp) 
     { 
      id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType, 
       await UserManager.GetSecurityStampAsync(user))); 
     } 

     // code removed that adds the role claims 

     if (UserManager.SupportsUserClaim) 
     { 
      id.AddClaims(await UserManager.GetClaimsAsync(user)); 
     } 
     return new ClaimsPrincipal(id); 
    } 
} 

回答

1

我想知道是否可以使用自定義聲明政策,但有實際的代碼,檢查授權處理程序中的聲明,以便聲明不會與每個HTTP請求一起傳遞,而是從授權cookie或數據庫獲取服務器端。

這絕對有可能。你可以這樣做:

public class Startup 
{ 
    public void ConfigureServices(IServiceCollection services) 
    { 
     services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>(); 

     services.AddAuthorization(options => 
     { 
      options.AddPolicy("Has-Edit-User-Profiles-Permission", builder => 
      { 
       builder.RequirePermission("Edit-User-Profiles"); 
      }); 
     }); 
    } 
} 

public class PermissionAuthorizationRequirement : IAuthorizationRequirement 
{ 
    public PermissionAuthorizationRequirement(string permission) 
    { 
     if (string.IsNullOrEmpty(permission)) 
     { 
      throw new ArgumentException("The permission cannot be null or empty.", nameof(permission)); 
     } 

     Permission = permission; 
    } 

    public string Permission { get; set; } 
} 

public class PermissionAuthorizationHandler : 
    AuthorizationHandler<PermissionAuthorizationRequirement> 
{ 
    private readonly UserManager<ApplicationUser> _userManager; 

    public PermissionAuthorizationHandler(UserManager<ApplicationUser> userManager) 
    { 
     if (userManager == null) 
     { 
      throw new ArgumentNullException(nameof(userManager)); 
     } 

     _userManager = userManager; 
    } 

    protected override async Task HandleRequirementAsync(
     AuthorizationHandlerContext context, 
     PermissionAuthorizationRequirement requirement) 
    { 
     if (context.User == null) 
     { 
      return; 
     } 

     var user = await _userManager.GetUserAsync(context.User); 
     if (user == null) 
     { 
      return; 
     } 

     // Use whatever API you need to ensure the user has the requested permission. 
     if (await _userManager.IsInRoleAsync(user, requirement.Permission)) 
     { 
      context.Succeed(requirement); 
     } 
    } 
} 

public static class PermissionAuthorizationExtensions 
{ 
    public static AuthorizationPolicyBuilder RequirePermission(
     this AuthorizationPolicyBuilder builder, string permission) 
    { 
     if (builder == null) 
     { 
      throw new ArgumentNullException(nameof(builder)); 
     } 

     if (string.IsNullOrEmpty(permission)) 
     { 
      throw new ArgumentException("The permission cannot be null or empty.", nameof(permission)); 
     } 

     return builder.AddRequirements(new PermissionAuthorizationRequirement(permission)); 
    } 
} 
+0

Thanks Pinpoint - 這是一個很好的例子。這將在很多角色聲明中起作用。我可以從id_token和access_token中刪除這些內容。但是,由於我使用的是AspNetRoleClaims表,Identity可以讓我「開箱即用」 - 這些許多聲明仍然存儲在Identity Authorization cookie中,現在我發現當我註銷我的HTTP Request標頭時太大。 – user1750537

+0

我想知道如果我可以阻止這個角色聲明被填充到身份cookie中,並且可能有一種方法可以直接查詢這個,一旦我點擊PermissionAuthorizationHandler。也許儘管最簡單的解決方案就是根本不使用AspNetRoleClaims表,並使用我自己的自定義Permissions表並從PermissionAuthorizationHandler中獲取這些表,如上所示。 – user1750537

+1

@ user1750537是的,你可以。一種選擇是創建您自己的'IUserClaimsPrincipalFactory'並將其註冊到DI容器中:https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNetCore.Identity/UserClaimsPrincipalFactory.cs。或者,您也可以調整您的'CreateTicketAsync'方法以刪除角色聲明。 – Pinpoint