net bearer asp asp.net asp.net-mvc asp.net-web-api asp.net-identity-2 asp.net-authorization

bearer - ¿Cómo puedo implementar una Autorización basada en Reclamos con ASP.NET WebAPI sin utilizar Roles?



oauth authentication asp net web api (1)

Tengo una aplicación ASP.Net WebAPI 2 que usa Reclamaciones. Los reclamos se almacenan como dos columnas adicionales en una tabla estándar Identity2 AspNetUsers:

CREATE TABLE [dbo].[AspNetUsers] ( [Id] INT IDENTITY (1, 1) NOT NULL, .... [SubjectId] INT DEFAULT ((0)) NOT NULL, [LocationId] INT DEFAULT ((0)) NOT NULL, CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC) );

He modificado la clase ApplicationUser de esta manera:

public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim> { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager, string authenticationType) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType ClaimsIdentity userIdentity = await manager.CreateIdentityAsync(this, authenticationType); // Add custom user claims here userIdentity.AddClaim(new Claim("SubjectId", this.SubjectId.ToString())); userIdentity.AddClaim(new Claim("LocationId", this.LocationId.ToString())); return userIdentity; } public int SubjectId { get; set; } public int LocationId { get; set; } }

En mi método de registro, agrego nuevos datos para SubjectId:

var user = new ApplicationUser() { UserName = model.UserName, SubjectId = 25, LocationId = 4 }; IdentityResult result = await UserManager.CreateAsync(user, model.Password);

¿Alguien puede ayudarme a decir cómo puedo ahora restringir el acceso a un controlador basado en este SubjectId en el nivel de controlador y también en el nivel de método con algo similar a esto?

[Authorize(SubjectId = "1,25,26")] [RoutePrefix("api/Content")] public class ContentController : BaseController { [Authorize(LocationId = "4")] [Route("Get")] public IQueryable<Content> Get() { return db.Contents; } [Authorize(SubjectId = "25")] [Route("Get/{id:int}")] public async Task<IHttpActionResult> Get(int id) { Content content = await db.Contents.FindAsync(id); if (content == null) { return NotFound(); } return Ok(content); }

Durante meses he estado buscando un ejemplo, pero aparte de alguna referencia al producto ThinkTexture y al siguiente enlace, no he encontrado nada

Actualizar:

#region Assembly System.Web.Http.dll, v5.2.2.0 // C:/Users/Richard/GitHub/abilitest-server/packages/Microsoft.AspNet.WebApi.Core.5.2.2/lib/net45/System.Web.Http.dll #endregion using System; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace System.Web.Http { // Summary: // Specifies the authorization filter that verifies the request''s System.Security.Principal.IPrincipal. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class AuthorizeAttribute : AuthorizationFilterAttribute { // Summary: // Initializes a new instance of the System.Web.Http.AuthorizeAttribute class. public AuthorizeAttribute(); // Summary: // Gets or sets the authorized roles. // // Returns: // The roles string. public string Roles { get; set; } // // Summary: // Gets a unique identifier for this attribute. // // Returns: // A unique identifier for this attribute. public override object TypeId { get; } // // Summary: // Gets or sets the authorized users. // // Returns: // The users string. public string Users { get; set; } // Summary: // Processes requests that fail authorization. // // Parameters: // actionContext: // The context. protected virtual void HandleUnauthorizedRequest(HttpActionContext actionContext); // // Summary: // Indicates whether the specified control is authorized. // // Parameters: // actionContext: // The context. // // Returns: // true if the control is authorized; otherwise, false. protected virtual bool IsAuthorized(HttpActionContext actionContext); // // Summary: // Calls when an action is being authorized. // // Parameters: // actionContext: // The context. // // Exceptions: // System.ArgumentNullException: // The context parameter is null. public override void OnAuthorization(HttpActionContext actionContext); } }


Puede lograr eso si anula el atributo Authorize . En tu caso, debería ser algo como esto:

public class ClaimsAuthorize : AuthorizeAttribute { public string SubjectID { get; set; } public string LocationID { get; set; } protected override bool IsAuthorized(HttpActionContext actionContext) { ClaimsIdentity claimsIdentity; var httpContext = HttpContext.Current; if (!(httpContext.User.Identity is ClaimsIdentity)) { return false; } claimsIdentity = httpContext.User.Identity as ClaimsIdentity; var subIdClaims = claimsIdentity.FindFirst("SubjectId"); var locIdClaims = claimsIdentity.FindFirst("LocationId"); if (subIdClaims == null || locIdClaims == null) { // just extra defense return false; } var userSubId = subIdClaims.Value; var userLocId = subIdClaims.Value; // use your desired logic on ''userSubId'' and `userLocId'', maybe Contains if I get your example right? if (!this.SubjectID.Contains(userSubId) || !this.LocationID.Contains(userLocId)) { return false; } //Continue with the regular Authorize check return base.IsAuthorized(actionContext); } }

En su controlador al que desea restringir el acceso, use el atributo ClaimsAuthorize lugar del Authorize normal:

[ClaimsAuthorize( SubjectID = "1,2", LocationID = "5,6,7")] [RoutePrefix("api/Content")] public class ContentController : BaseController { .... }