如何在不使用角色的情况下使用 ASP.NET WebAPI 实现基于声明的授权?
Posted
技术标签:
【中文标题】如何在不使用角色的情况下使用 ASP.NET WebAPI 实现基于声明的授权?【英文标题】:How can I implement Claims-Based Authorization with ASP.NET WebAPI without using Roles? 【发布时间】:2015-01-04 12:42:09 【问题描述】:我有一个使用声明的 ASP.Net 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)
);
我已经像这样修改了 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;
在我的注册方法中,我为 SubjectId 添加了新数据:
var user = new ApplicationUser()
UserName = model.UserName,
SubjectId = 25,
LocationId = 4
;
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
谁能帮我告诉我现在如何在控制器级别和方法级别基于此 SubjectId 限制对控制器的访问,类似于以下内容:
[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);
几个月来,我一直在寻找一个示例,但除了对 ThinkTexture 产品和以下链接的一些参考之外,我什么也没找到
更新:
#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】:您可以通过覆盖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);
在您希望限制访问的控制器中,使用ClaimsAuthorize
属性而不是普通的Authorize
属性:
[ClaimsAuthorize(
SubjectID = "1,2",
LocationID = "5,6,7")]
[RoutePrefix("api/Content")]
public class ContentController : BaseController
....
【讨论】:
非常感谢您的回答。你能给我一些建议,告诉我如何设法获得备用和两个级别的授权。在我的问题中,我提到了两种类型的索赔。 SubjectId 和 LocationId 声明。我知道您建议如何覆盖,但如果我有两种不同类型的 ClaimsAuthorize,我不确定如何做到这一点。 @marifemac 你仍然可以用一个属性来做,给我几分钟我会编辑答案。 @marifemac 已编辑,是否更好地回答了您的问题? 我遇到了问题,因为 AuthorizeAttribute 中没有 AuthorizeCore。 @marifemac 是的,但是看看第一个答案(12 票,而不是被接受的),它会在一条评论中比我更好地解释它***.com/questions/12629530/…以上是关于如何在不使用角色的情况下使用 ASP.NET WebAPI 实现基于声明的授权?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 Visual Studio 的情况下使用 ASP.NET MVC 实现站点?
如何在不使用 Visual Studio 的情况下使用 ASP.NET MVC 实现站点?
如何在不刷新的情况下使用 Ajax 在 ASP.NET MVC 中保存表单数据
ASP.NET CORE MVC 选择标签助手 - 如何在不使用 ModelView 的情况下设置选定值