Secure web API with form authentication (authorization) and basic authentication (message handler) together

I am trying to use form authentication (filter attribute) and basic authentication (message handler). I know that the web API pipeline runs before a message handler than with filters.

I tried everything and I tried to search a lot in google, but I can’t find a solution, I can only perform authentication and authorization, but not together.

the code:

Testcontroller.cs

public class TestController : ApiController
{
    private readonly worldEntities  _db = new worldEntities();

    // GET api/Country
    [Authorize]
    public Capital Get()
    {

        var capital = new Capital
        {
            CapitalCountry = _db.cities.FirstOrDefault(),
            Country = _db.countries.FirstOrDefault()
        };
        capital.Cities = _db.cities.Where(s => s.CountryCode == capital.Country.Code);
        _db.SaveChanges();
        return capital;

    }


    // Post api/Country
    public Capital Post()
    {

        var capital = new Capital
        {
            CapitalCountry = _db.cities.FirstOrDefault(),
            Country = _db.countries.FirstOrDefault()
        };
        capital.Cities = _db.cities.Where(s => s.CountryCode == capital.Country.Code);
        _db.SaveChanges();
        return capital;

    }

}

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.MessageHandlers.Add(new BasicAuthMessageHandler());

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

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

BasiAuthMessagHandle.cs

public class BasicAuthMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var headers = request.Headers;
        if (headers.Authorization != null && headers.Authorization.Scheme == "Basic")
        {
            var userPwd = Encoding.UTF8.GetString(Convert.FromBase64String(headers.Authorization.Parameter));
            var user = userPwd.Substring(0, userPwd.IndexOf(':'));
            var password = userPwd.Substring(userPwd.IndexOf(':') + 1);
            // we suppose that it ok
            var principal = new GenericPrincipal(new GenericIdentity(user), null);
            PutPrincipal(principal);

        }

        return base.SendAsync(request, cancellationToken);
    }

    private void PutPrincipal(IPrincipal principal)
    {
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
        }
    }


}

AuthController.cs

public class AuthController : ApiController
{

        public string Get(string id)
        {
            FormsAuthentication.SetAuthCookie(id ?? "FooUser", false);
            return "You are autenthicated now";
        }

}

Web.config

<authentication mode="Forms" />

Thank you very much!

+4
source share
2 answers

, -API (. Toan). , -api Autodesk Forms . , , .

http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

-. , . , , . , ASP.NET Web API, MVC , .

, -. Web API (Get, Post, Put, Delete, Options), Controller.User IPrincipal, , IsAuthenticated bool . , [AllowAnonymous] [Authorize].

: SSL - , . Auth

, MVC4 -API BaseApiController

    public BaseApiController()
    {
        CurrentUser = new ScrubbedUser(User);
    }
    protected ScrubbedUser CurrentUser { get; set; }

ScrubbedUser ( /), ,

public class ScrubbedUser
    {
        private IPrincipal Principal { get; set; }
        public ScrubbedUser(string principal)
        {
            Principal = null;
            if (string.IsNullOrEmpty(principal))
            {
                Profile = GetDefaultProfile();
            }
            else
            {
                Profile = GetUserProfile(principal);
            }
            //Get User Memberships
            Memberships = GetUserMemberships();
            Settings = GetUserSettings();
        }
        public SurgeStreetUser(IPrincipal principal) 
        {
            Principal = principal;
            if (Principal == null
                || Principal.Identity == null
                || Principal.Identity.IsAuthenticated == false
                || string.IsNullOrEmpty(Principal.Identity.Name))
            {
                Profile = GetDefaultProfile();
            }
            else
            {
                Profile = GetUserProfile(Principal.Identity.Name);
            }
            //Get User Memberships
            Memberships = GetUserMemberships();
            Settings = GetUserSettings();
        }
        public UserProfile Profile { get; private set; }
        public List<V_UserMembership> Memberships { get; private set; }
        public List<Setting> Settings { get; private set; }

        private UserProfile GetDefaultProfile()
        {
            //Load an Anonymous Profile into the ScrubbedUser instance any way you like
        }
        private UserProfile GetUserProfile(string userName)
        {
            //Load the UserProfile based on userName variable (origin is Principle Identity Name
        }
        private List<V_UserMembership> GetUserMemberships()
        {
            //Load User Memberships or Roles from Database, Cache or Session
        }
        private UserProfile PopulateCurrentUser(UserProfile userProfile)
        {
            var user = new UserProfile
            {
                //Convenience Method to clone and set a Profile Property
            };
            return user;
        }
        private List<Setting> GetUserSettings()
        {
            //Get the User Settings or whatever
        }
        //Convenience to return a JSON string of the User (great to use with something like Backbone.js)
        private dynamic JSONRecord
        {
            get
            {
                return new
                {
                    CustId = Profile.CustId,
                    UserName = Profile.UserName,
                    UserId = Profile.UserId,
                    Email = Profile.Email,
                    FirstName = Profile.FirstName,
                    Language = Profile.Language,
                    LastActivityDate = Profile.LastActivityDate,
                    LastName = Profile.LastName,
                    DebugOption = Profile.DebugOption,
                    Device = Profile.Device,
                    Memberships = Memberships,
                    Settings = Settings
                };
            }
        }
    }

CurrentUser , , -. [] -API

public class ListController : BaseApiController
{
    //main is "global"
    public dynamic Get(string id)//JObject values)
    {
        //I can test here for anonymous as well, even if I allow anonymous

        //Example using my own convention on User Profile Class populated by ScrubbedUser constructor
        if (CurrentUser.Profile.CustId == "public")
        {
            return HttpStatusCode.Forbidden;
        }
        //Redundant Code
        if (!User.Identity.IsAuthenticated)
        {
            return HttpStatusCode.Forbidden;
        }
        string filterExt = string.IsNullOrEmpty(id) || id=="global"
            ? "*" : id;
        return ListRepository.GetList(filterExt, SSUser);
    }
    [Authorize]
    public dynamic Post(JObject values)
    {
        //Just a sample, this will not fire unless the user is authenticated
        return CurrentUser.JSONRecord;
    }
}
+2

Source: https://habr.com/ru/post/1538482/


All Articles