【问题标题】:ASP.NET web api - Set custom IIdentity or IPrincipalASP.NET web api - 设置自定义 IIdentity 或 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

【问题讨论】:

    标签: asp.net-mvc asp.net-web-api


    【解决方案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.IsAuthenticatedUser.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
        
        
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-11-07
          • 2017-10-14
          • 2012-05-31
          • 2011-01-31
          • 2015-05-05
          • 2015-10-07
          • 2023-04-08
          • 2015-11-10
          相关资源
          最近更新 更多