I have an ASP.Net WebAPI 2 Application that uses Claims. The claims are stored as two additional columns in a standard Identity2 AspNetUsers table:
我有一个ASP。使用索赔的WebAPI 2应用程序。声明作为两个附加列存储在标准的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)
);
I have modified the ApplicationUser class like this:
我修改了ApplicationUser类如下:
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; }
}
In my register method I add in new data for the SubjectId:
在我的register方法中,我为受试者添加了新的数据:
var user = new ApplicationUser() {
UserName = model.UserName,
SubjectId = 25,
LocationId = 4
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
Can someone help tell me how I can now go about restricting access to a controller based on this SubjectId at the controller level and also at the method level with something similar to this:
有人能告诉我,我现在怎么能限制对控制器的访问,在控制器层面上,也在方法层面上,使用类似的东西:
[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);
}
For months now I have been looking for an example but other than some reference to ThinkTexture product and the following link I have found nothing
几个月来,我一直在寻找一个例子,但除了参考ThinkTexture产品和下面的链接,我什么也没找到
Update:
更新:
#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);
}
}
1 个解决方案
#1
34
You can achieve that if you override the Authorize
attribute. In your case it should be something like this:
如果重写了Authorize属性,就可以实现这一点。你的情况应该是这样的:
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);
}
}
In your controller that you wish to restrict access to, use the ClaimsAuthorize
attribute instead of the normal Authorize
one:
在您希望限制访问的控制器中,使用ClaimsAuthorize属性而不是常规的Authorize属性:
[ClaimsAuthorize(
SubjectID = "1,2",
LocationID = "5,6,7")]
[RoutePrefix("api/Content")]
public class ContentController : BaseController
{
....
}
#1
34
You can achieve that if you override the Authorize
attribute. In your case it should be something like this:
如果重写了Authorize属性,就可以实现这一点。你的情况应该是这样的:
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);
}
}
In your controller that you wish to restrict access to, use the ClaimsAuthorize
attribute instead of the normal Authorize
one:
在您希望限制访问的控制器中,使用ClaimsAuthorize属性而不是常规的Authorize属性:
[ClaimsAuthorize(
SubjectID = "1,2",
LocationID = "5,6,7")]
[RoutePrefix("api/Content")]
public class ContentController : BaseController
{
....
}