This is not a problem. You have a variety of options available to you. One approach is to blend Forms Authentication with your own security model.
The basic idea is to let Forms Auth create and manage a ticket (in the form of an encrypted ticket) for the logged-in user. The ticket is used to determine whether or not someone is logged in, and who they are. You can then mix in any additional security related logic on top of that.
To process the login request, you just have a controller and action like you normally would. Note: in the example below, I am making some assumptions about LoginViewModel, the service you are using to authenticate, and the object it returns if any. You'll have to sub in your actual logic.
public ActionResult Login(LoginViewModel model)
{
// make sure the user filled out the login fields correctly
if (!ModelState.IsValid) return View(model);
// authenticate the user here
var authenticatedUser = AuthorizeUserUsingRemoteWebService(model.Username, model.Password);
if (authenticatedUser.IsAuthenticated)
{
// create forms auth ticket cookie and redirect to the home page
FormsAuthentication.SetAuthCookie(authenticatedUser.Username);
return RedirectToAction("Index", "Home");
}
// authentication failed, so show the login page again
return View(model);
}
In addition to that, you may have an HTTP module that handles the AuthenticateRequest event. Your module will be registered after the Forms Auth HTTP module, so it will have already processed whether or not the user is logged in. What you want to do is look up additional information if they are logged in, to get roles and such.
public class CustomAuthHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest += new EventHandler(OnAuthenticateRequest);
}
void OnAuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = appObject.Context;
// user isn't logged in, so don't do anything else
if (!context.User.Identity.IsAuthenticated) return;
// look up the roles for the specified user, returning the role names as an array of strings
string[] roles = LookupUserRolesFromWebService(context.User.Identity.Name);
// replace the current User principal with a new one that includes the roles we discovered for that user.
context.User = new GenericPrincipal(new GenericIdentity(context.User.Identity.Name), roles);
}
}
You'll register the HTTP module in your web.config:
<httpModules>
<add name="CustomAuthHttpModule"
type="MyAssembly.CustomAuthenticationModule, MyAssembly" />
</httpModules>
You can now use the User object in your MVC controllers and views, the AuthenticatedAttribute, etc.
However, I'd recommend that you cache the results of looking up a user's roles so you don't hammer your web service. I'll leave that up to you.