You can use the token authentication mechanism for WebApi2.
The stream will be something like this:
users send you an https request:
https: // yourApiUrl / Token
The request content type must be:
application/x-www-form-urlencoded
body should include:
grant_type=password&username=yourWebsFormsUsername&password=yourWebFormsPassword
your OWIN startup class will look something like this:
public partial class Startup { public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } public static string PublicClientId { get; private set; } public void ConfigureAuth(IAppBuilder app) { app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); PublicClientId = "self"; OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/Token"), Provider = new YourOAuthProvider(), AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AllowInsecureHttp = true, }; app.UseOAuthBearerTokens(OAuthOptions); } }
Please note that the ThOutProvider above is an important part. This is your custom provider that will check your username and password for what you have. In your case, the aspnet_membership table. This check is performed below in the RequestHasValidCredentials method:
public class YourOAuthProvider : OAuthAuthorizationServerProvider { public string apikey = string.Empty; public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { if (RequestHasValidCredentials(context.UserName, context.Password)) { var id = new ClaimsIdentity(context.Options.AuthenticationType); id.AddClaim(new Claim("username", context.UserName)); context.Validated(id); } else { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } } }
the answer that your user reaches the above will be a token that will include the username or any other information that you added to the context in the above method:
id.AddClaim(new Claim("username", context.UserName));
The response from the above api token call will be something like this:
{ "access_token": "9TIpW2m2rUbB_Bmb7kKAQ9GH4hgfnKF8g3fL0tAre2gcFjI45fajmG6qdOJe-A", "token_type": "bearer", "expires_in": 1209599 }
your user will need to pass this token as the Http Authorization header for all API calls. They should convey this when using a carrier scheme, for example:
Bearer 9TIpW2m2rUbB_Bmb7kKAQ9GH4hgfnKF8g3fL0tAre2gcFjI45fajmG6qdOJe-A
since this token contains the username, you can find out who this user is. The last thing is now to read this token and get the username. To do this, you need to create a custom Authorize attribute and decorate it with a controller or methods.
public class YourAuthorizeAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) { var ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect(actionContext.Request.Headers.Authorization.Parameter); string username = claims.Where(x => x.Type == "username").FirstOrDefault(); base.OnAuthorization(actionContext); } }
all other user authorization logic can be added here as soon as you have a username.
You can transfer other user information during token generation and read it here. (in case it is necessary for any other special authorization logic.)
Its a lengthy approach, but it will work with any credential store.