ASP.NET web api - 设置自定义 IIdentity 或 IPrincipal
Posted
技术标签:
【中文标题】ASP.NET web api - 设置自定义 IIdentity 或 IPrincipal【英文标题】:ASP.NET web api - Set custom IIdentity or IPrincipal 【发布时间】:2015-10-22 18:45:50 【问题描述】:在我们的 asp.net mvc/web api 项目中,我们希望使用AuthorizeAttribute
自定义授权。我们注意到有两种不同的AuthorizeAttribute
,一种在System.Web.MVC
命名空间中用于MVC,另一种在System.Net.Http
命名空间中用于Web api。
它在MVC中工作,我们的代码是这样的:
public class MyPrincipal : IPrincipal
//some custom properties
public bool IsValid()
//custom authentication logic
private IIdentity identity;
public IIdentity Identity
get return this.identity;
public bool IsInRole(string role)
return true;
//override AuthorizeCore
public class MyAuthorizeAttribute : AuthorizeAttribute
protected override bool AuthorizeCore(HttpContextBase httpContext)
MyPrincipal user = new MyPrincipal();
if (user.isValid())
httpContext.User = user;
else
httpContext.Response.Redirect("~/Common/NoAuthorize", true);
[MyAuthorizeAttribute]
public class BaseMyController : Controller
protected virtual new MyPrincipal User
get return HttpContext.User as MyPrincipal;
然后在MVC控制器中,我们可以通过MyPrincipal
用户属性获取用户信息。
但是,当我们开始在web api中使用相同的方式时,我们发现web api没有HttpContext
属性,并且在System.Web.Http.AuthorizeAttribute
中,被覆盖的方法接受HttpActionContext
参数,它也有没有HttpContext
属性或其他我们可以设置MyPrincipal
实例的地方。
我注意到System.Web.Http.AuthorizeAttribute
总结说
指定验证请求的 IPrincipal 的授权过滤器
似乎还有其他方法可以设置IPrincipal
实例。
我不知道,有什么好的建议吗?对了,为什么asp.net web api控制器没有HttpContext
?有没有关于它的设计模式?
相关问题 ASP.NET MVC - Set custom IIdentity or IPrincipal
【问题讨论】:
【参考方案1】:我实现了一些东西作为概念验证,主要遵循以下内容:Authentication Filters in ASP.NET Web API 2
对于 Web API,您可以创建一个属性 IAuthenticationFilter。 如果我没记错的话,您可以将其作为过滤器添加到 WebApiConfig 中的全局过滤器中
config.Filters.Add(new YourAuthenticationAttribute());
或者您可以将其用作 api 控制器/方法的属性。
然后你可以实现AuthenticateAsync,获取请求的授权头,检查scheme,验证参数,如果都有效,设置principal。
我认为这个想法是您可以在一个链中添加多个这些过滤器,它们都可以根据一组特定的要求进行身份验证,例如他们寻找的方案,以及在链中设置主体的某个位置,或者挑战被返回。
public class YourAuthenticationAttribute : Attribute, IAuthenticationFilter
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
HttpRequestMessage request = context.Request;
if (request.Headers.Authorization != null &&
request.Headers.Authorization.Scheme.Equals("yourScheme", StringComparison.OrdinalIgnoreCase))
// get the value sent with the header.
string authParam = request.Headers.Authorization.Parameter;
// do some validation on the parameter provided...
// if it's all valid, create a principal with claims:
List<Claim> claims = new List<Claim>()
new Claim(ClaimTypes.Name, "Eddie Admin"),
new Claim(ClaimTypes.Role, "Admin"),
// new Claim(ClaimTypes.Role, "Delete"),
;
// create an identity with the valid claims.
ClaimsIdentity identity = new ClaimsIdentity(claims, "yourScheme");
// set the context principal.
context.Principal = new ClaimsPrincipal(new[] identity );
创建主体时,您可以应用声明,并根据正常的授权属性检查这些声明。例如
[Authorize(Roles = "Admin")]
除此之外我还没有使用过它,但希望这会为您指明正确的方向。
【讨论】:
谢谢!context.Principal
正是我需要的,但我们的保护是基于asp.net web api,而不是web api 2,我无法实现接口IAuthenticationFilter
。幸运的是,你的链接[ ASP.NET Web API 2 中的身份验证过滤器](asp.net/web-api/overview/security/authentication-filters) 对我有很大帮助,我在 asp.net web api Basic Authentication in ASP.NET Web API 中找到了另一种方法。它实现了一个 http 模块。
[Authorize(Roles = "Admin")] 给我“此请求的授权已被拒绝。”当我定义我的自定义授权时,它可以工作。公共类 MyCustomAuthorize : AuthorizationFilterAttribute 公共覆盖无效 OnAuthorization(HttpActionContext actionContext) if (!actionContext.ControllerContext.RequestContext.Principal.IsInRole("Admin")) actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized); base.OnAuthorization(actionContext); 最后,[MyCustomAuthorize] public class EmployeeController : ApiController 【参考方案2】:
这个AuthorizeAttribute
实现对我有用。它是为Http Basic Auth 设计的,但显然我也想从ApiController
内部获取User.Identity.IsAuthenticated
和User.Identity.Name
,这很有效:
public class ApiAuthAttribute : AuthorizeAttribute
public override void OnAuthorization(HttpActionContext actionContext)
var session = (ISession)actionContext.Request.GetDependencyScope().GetService(typeof(ISession));
if (actionContext.Request.Headers.Authorization != null)
var authConcat = Encoding.UTF8.GetString(Convert.FromBase64String(actionContext.Request.Headers.Authorization.Parameter));
var email = authConcat.Split(':')[0];
var password = authConcat.Split(':')[1];
var user = session.Query<UserAccount>().SingleOrDefault(u => u.Email == email);
if (user != null && user.IsAuthenticated(password))
actionContext.ControllerContext.RequestContext.Principal = new GenericPrincipal(new GenericIdentity(user.Email), new string[] );
return; // and continue with controller
actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotFound);
【讨论】:
【参考方案3】:我记得在 WebApi 中我只能使用 ControllerContext。但我不确定究竟是为什么。根据我的阅读,HttpContext 是线程静态的,但 WebApi 中的所有内容或多或少都是异步的。看看这个topic,说不定会回答一些问题。
【讨论】:
【参考方案4】:只需扩展您的IPrincipal
。
public static class IPrincipalExtension
public static bool IsValid(this IPrincipal p)
// your custom validation
return true;
现在引用您的命名空间并像这样使用。
public class MyAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
var valid = actionContext.RequestContext.Principal.IsValid(); // this will return boolean
// your code here
【讨论】:
以上是关于ASP.NET web api - 设置自定义 IIdentity 或 IPrincipal的主要内容,如果未能解决你的问题,请参考以下文章
asp.net core 2.0 web api基于JWT自定义策略授权
如何自定义 ASP .NET Web API JWT 令牌响应?