ASP.NET web api - Set custom IIdentity or IPrincipal

后端 未结 4 1138
忘掉有多难
忘掉有多难 2021-02-09 06:29

In our asp.net mvc/web api project, we want to customize the authorization using AuthorizeAttribute. We have noticed that there are two different AuthorizeAtt

相关标签:
4条回答
  • 2021-02-09 06:54

    I implemented something as a proof of concept following mostly this: Authentication Filters in ASP.NET Web API 2

    For Web API you can create an Attribute, IAuthenticationFilter. If I remember rightly, you can add it as a filter to the global filters in WebApiConfig

    config.Filters.Add(new YourAuthenticationAttribute());
    

    Or you can use it as an attribute on the api controller/ method.

    You can then implement AuthenticateAsync, get the request's authorization header, check the scheme, and validate the parameter, and if all is valid, set the principal.

    I think the idea is that you can add multiple of these filters in a chain and they can all authenticate against a specific set of requirements, like the scheme they look for, and somewhere in the chain the principal gets set, or a challenge is returned.

    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 });
    

    When creating the principal you can apply claims and these are checked against the normal authorize attribute. e.g.

    [Authorize(Roles = "Admin")]
    

    I haven't used it beyond doing this, but hopefully this points you in the right direction.

    0 讨论(0)
  • 2021-02-09 07:01

    Just extend your IPrincipal.

    public static class IPrincipalExtension
    {
       public static bool IsValid(this IPrincipal p)
       {
           // your custom validation
           return true;
       }
    }
    

    Now reference your namespace and use like this.

    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
    
    
        }
    }
    
    0 讨论(0)
  • 2021-02-09 07:05

    This AuthorizeAttribute implementation worked for me. It's designed for Http Basic Auth but obviously I want to get the User.Identity.IsAuthenticated and User.Identity.Name from inside a ApiController too and this works:

    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);
        }
    }
    
    0 讨论(0)
  • 2021-02-09 07:18

    I remember that in WebApi I could only use ControllerContext. But I'm not sure exactly why. From What I read, HttpContext is thread static, but everything in WebApi is more or less async. Take a look at this topic, maybe it will answer some questions.

    0 讨论(0)
提交回复
热议问题