So, as promised, here is my guide of using the new ASP NET MVC Identity system with YAF's Memebrhip Provider.
For those who know and have read up on Microsoft's latest experiment - Mictosoft has adopted OWIN (Open Web Interface) and, in particular, their own adaptation of OWIN called project Katana for handling authentication in MVC 5 (And onwards, or -so- they say).
What OWIN is, in plain English, is a mechanism that allows the developer to enable as many OWIN middleware components (OWIN's term for functionality implemented by various providers) in the hosting service - a lightweight means of only loading what you need to run. For more details on OWIN and Katana, this post has helped me a lot in understanding the basics:
http://msdn.microsoft.com/en-us/magazine/dn451439.aspx
Now, one of the interesting things in MVC 5 when using OWIN are these two entries in web. config:
This, along with YAF running memembership provider had me confused for a long while - how does one use membership provider, which is tied to the FormsAuthentication parameter in web.config, when we now have to remove FormsAuthentication altogether from our web. config?
After many sleepless nights of frustration, and a few stack overflow visits, I came across the following post that revealed a huge truth:
http://brockallen.com/2012/06/04/membership-is-not-the-same-as-forms-authentication/
The title is a giveaway, but basically the truth of the matter is - membership and FormsAuthentication are not tied together; a common misconception plaguing many developers (including yours truly) for many a year. Poof. Out the window. Gone.
With that in mind, I integrated yaf 'net's web .config entries into my MVC 5 web config (excluding the FormsAuthentication) bit. Still paddling in unknown waters, I decided to use common sense. Hrm..There. I integrated membership, role, profile in web. config. But I felt like I was missing something important. Back to looking at YAF .NET's original web config:
now, I've already said, we CANNOT include the above in MVC 5.
YAF defines a name for its cookie on hello called .YAFNET_Authentication. Now, I am not SURE if this is of any important, or not, but call me cautious. Your MVC 5 project has created a Startup.cs class under App_Start (this can be configured to be anywhere - if you are familiar with OWIN, you're looking for the file containing your Configuration method). In the standard MVC 5 template, there's a call to ConfigAuth from within Configuration. Here's part of the magic that's taking place in ConfigAuth:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
......
CookieName = ".YAFNET_Authentication"
......
});
And this is where you can tune your cookie setup in OWIN. Notice the name I gave my cookie? Just in case, I've used the default name used in YAF NET Web Config.
Now, last but not least - disable registration in YAF NET, and Log In - you will be handling this from your own site. Most of the pipeline is already there. And here is the excerpt from my code:
For CREATING a user:
public async Task Register(RegisterViewModel model) {
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
//persist the user in the forum as well.
CreateYAFUser(model.UserName, model.Password, model.Email);
....
For Signing in with an exertnal provider (Facebook/Twitter etc etc):
public async Task ExternalLoginConfirmation(RegisterViewModel model, string returnUrl) {
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Manage");
}
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
CreateYAFUser(model.UserName,model.Password,model.Email);
return RedirectToLocal(returnUrl);
}
meaning :
Whenever you register someone locally, or whenever you're authenticating someone, register them in your YAF DB as well, using YAF methods. Which mehods you as? Here's the implementation for CreateYAFUser:
private static void CreateYAFUser(string sUsername, string sPassword, string email)
{
if (!YAFHelper.YAFUserExists(email))
{
YafMembershipProvider mb = (YafMembershipProvider)System.Web.Security.Membership.Providers["YafMembershipProvider"];
int? forumUserID = 0;
if (!mb.ValidateUser(sUserName, sPassword))
{
MembershipCreateStatus status;
MembershipUser forumUser = mb.CreateUser(sUserName, sUserName, sUserName, "question", "answer", true, null, out status);
// create the user in the YAF DB as well as sync roles...
forumUserID = RoleMembershipHelper.CreateForumUser(forumUser, 1);
RoleMembershipHelper.SetupUserRoles(1, sUserName);
RoleMembershipHelper.AddUserToRole(sUserName, "Registered");
// create empty profile just so they have one
YafUserProfile userProfile = YafUserProfile.GetProfile(sUserName);
userProfile.Homepage = "fwd.com";
// setup their inital profile information
userProfile.Save();
}
else
{
DataTable results = (DataTable)YAF.Classes.Data.LegacyDb.UserFind(1, false, sUserName, sUserName, sUserName, null, null);
//DataTable results = YAF.Classes.Data.DB.UserFind(1, false, sUserName, sUserName);
if (results.Rows.Count > 0)
{
forumUserID = (int)results.Rows[0]["UserID"];
}
}
}
And that's about it - for the first step that is. This works for me just fine. Every user I create on my site is persisted in the forums. Every time someone logs ont o my site whether locally or through an external provider, they are also logged on the Forums.
It's imperitive you register the same username on your site as you do when you call the forum's create user, as that username is being used (in my understanding) by the YAF membership provider. Any questions or problems, please respond to this thread and I'll do my best to lend a hand (though I am not an expert).
And if any YAF Admins want to replace the CreateYAF method with something more better and current, please feel free :)