YAFLogo

Posted by: evak2979 - Monday, 12 May 2014 20:04:23
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: [quote] ... 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: [quote]app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), ...... CookieName = ".YAFNET_Authentication" ...... });[/quote] 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: [quote]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. [b] CreateYAFUser(model.UserName, model.Password, model.Email);[/b] .... 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); [b]CreateYAFUser(model.UserName,model.Password,model.Email);[/b] return RedirectToLocal(returnUrl); }[/quote] 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: [quote]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"]; } } }[/quote] 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 :)

Posted by: deggen40 - Monday, 16 June 2014 19:16:55
Did you have to do anything else to get login to work? I tried setting the cookiename = .YAFNET_Authentication, but that does not seem to be working.

Posted by: evak2979 - Monday, 16 June 2014 19:20:44
what are you trying to do exactly? :)

Posted by: deggen40 - Monday, 16 June 2014 19:21:54
I am trying to log in a user that I have created for both my site and the forum.

Posted by: evak2979 - Monday, 16 June 2014 19:31:46
What authentication are you using on your site?

Posted by: deggen40 - Monday, 16 June 2014 19:32:46
I'm using the OWIN authentication that comes with MVC5.

Posted by: evak2979 - Monday, 16 June 2014 19:39:21
You need to ensure the following: Users need to have the same username/email on the forums as they do on the site. When you create a user on your site, whether externally or internally, use the create user for YAF I have posted. You have to remove forms authentication (if it is there) on your site config, from when you merged the web configs. Give the cookie the same name as the above. Now, once you log on with a user who has the same username and email as one in the forums, and you navigate to the forum, it will work.

Posted by: deggen40 - Monday, 16 June 2014 19:55:47
Could you help me out with this line a bit. I can't seem to find the bit of code to detect if a user exists. YAFHelper.YAFUserExists(email) Thanks! EDIT: I found what I needed to call (YAF.Core.UserMembershipHelper.UserExists()).

Posted by: evak2979 - Monday, 16 June 2014 20:03:20
No problem, glad it works :)

Posted by: deggen40 - Monday, 16 June 2014 21:23:30
This works perfectly. Thanks for posting this! The only problem I am having now is that I cannot log in with the (host) Admin user that was created when the forum was installed. Can I easily change a created user to the admin type?

Posted by: Zero2Cool - Monday, 16 June 2014 22:45:24
[quote=deggen40;64010]This works perfectly. Thanks for posting this! The only problem I am having now is that I cannot log in with the (host) Admin user that was created when the forum was installed. Can I easily change a created user to the admin type?[/quote] What happens when you try using the password reset feature on the Admin user?

Posted by: deggen40 - Tuesday, 17 June 2014 14:30:59
EDIT: I tried using the below to reset the password but it is not working either. mb.ResetPassword only returned null and I am not being logged into both YAF and my dev site. YafMembershipProvider mb =(YafMembershipProvider)System.Web.Security.Membership.Providers["YafMembershipProvider"]; var reset = mb.ResetPassword(user.UserName, model.Password); Is there a way that I can install the database without setting up an admin or also create the user on my mvc site?

Posted by: deggen40 - Tuesday, 17 June 2014 15:30:27
I think I have this figured out now. I created another user with the Role of administrator and in the YAF_User table I set Flags = 3 for that user.

Posted by: silentcid - Thursday, 19 June 2014 01:19:52
I've been looking to add YAF into a new MVC 5 project. Do I follow the YAF.NET Integration in to an existing ASP.NET Application tutorial with this tutorial? If so, do I use the SampleWebApplication to do it or the manually integrate one? edit: I just been trying to integrate it with the regular install of yaf. I just got done with the cookies step of this tutorial. Right now, if I build and go into localhost/forum it gives me a 404 error saying it cannot find /forum/Forum.aspx. If I go to forum/install it will allow me to install the forums. I can get in also just fine with /forum/default.aspx. If I click on any of the links, it will give me the same 404 error. Not quite sure how to fix that. Anyone have an idea what it could be? edit 2: I fixed my problem, it looks like my urlrewrite wasn't setup properly. Just need to make my actual MVC5 page to be the one to show up first.

Posted by: silentcid - Friday, 20 June 2014 02:50:56
The line: if (!YAF.Core.UserMembershipHelper.UserExists()) is saying, "No overload for method 'UserExists' takes 0 arguments seems to be where I'm stuck on currently. Not sure how to fix this particular line. edit: nvm I fixed my problem.

Posted by: Mikael - Tuesday, 24 February 2015 16:53:36
Hello, I try to integrate a forum in a existing .net MVC website. For now I don't want to merge the authentication. I use the MVC authentication for the website and the default YAF authentication on the forum. I followed this tutorial : https://github.com/YAFNET/YAFNET/wiki/YAF.NET-Integration-in-to-an-existing-ASP.NET-Application My problem is that it seems I can log in (I enter my login and my password and I haven't error message), but when I am redirected on the homepage I'm not connected. Do you have an idea to solve this problem ?

Posted by: mattharper - Sunday, 11 October 2015 21:27:08
I cannot thank you enough for posting this. I have struggled with this for the past week. I understood perfectly well how MVC membership and profiles work. The part that I was missing was simply that I don't need to utilize the Forms Auth for YAF. This was driving me insane. Genius to try the cookie name in existing Startup.Auth for MVC. I was a bout to manually maintain a sych between the two since I wasted so much time on this. I am going to add a little more code here for anyone else coming to this post. If you have the the default account controller from the MVC Template from VS.NET (AccountController.cs), here are the changes you need to make to it. 1. Add the references. [quote] using YAF.Utils; using YAF.Core; using System.Web.Security; using YAF.Providers.Membership; using System.Data; [/quote] 2. Alter Register [quote] // POST: /Account/Register [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 // Send an email with this link // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here"); [b] //mjh -- Persist the user in the YAF forums as well. CreateYAFUser(user.UserName, model.Password, model.Email);[/b] return RedirectToAction("Index", "Secure"); } AddErrors(result); } // If we got this far, something failed, redisplay form return View(model); } [/quote] 3: ExternalLoginConfirmation [quote] // POST: /Account/ExternalLoginConfirmation [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) { if (User.Identity.IsAuthenticated) { return RedirectToAction("Index", "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.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user); if (result.Succeeded) { result = await UserManager.AddLoginAsync(user.Id, info.Login); if (result.Succeeded) { await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); [b] CreateYAFUser(user.UserName, user.PasswordHash, model.Email);[/b] return RedirectToLocal(returnUrl); } } AddErrors(result); } ViewBag.ReturnUrl = returnUrl; return View(model); } [/quote] 4. Add CreateYAFUser (I added mine to AccountController as static. Put it where ever you want.) [quote] #region YAF User Sync with MVC Membership private static void CreateYAFUser(string sUserName, string sPassword, string email) { if (!UserMembershipHelper.UserExists(sUserName, email)) { YafMembershipProvider mb = (YafMembershipProvider)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"]; } } } } #endregion [/quote] 5. Fix login and register links in YAF or remove them completely. [quote] Use something like this depending on your particular site structure for the YAF Links https://localhost:44300/Account/VerifyCode/?provider=matt&returnUrl=%2Fforum%2FForum.aspx&rememberMe=true and inside VerifyCode do a redirect to returnURL [/quote] Thanks Again!

Posted by: marcelocabrera - Sunday, 28 February 2016 03:06:58
HI Jumping in late on this.... I followed your example and it always seems to find the user as an existing user, in other words: if (!UserMembershipHelper.UserExists(sUserName, email)) always returns true, so I think it is looking in the MVC 5 indentity tables, not on the YAF user tables, how do I know the static class YAF.Core.UserMembershipHelper is using the right tables? Thanks, MC

Posted by: clubnp - Saturday, 16 April 2016 23:23:29
Hate to necro this thread, but I think its pretty relevant and useful if someone has the answer... I'm a fairly experienced web forms programmer, currently learning MVC and wanted to implemented YAF into a site. In the above post user's mention this line: DataTable results = (DataTable)YAF.Classes.Data.LegacyDb.UserFind(1, false, sUserName, sUserName, sUserName, null, null); But LegacyDb.UserFind no longer exists in the current source code. It looks like the current code is using some sort of (I'm guessing) dependency injection?? I'm not really sure how to do what I need in this scenario. Is there an alternative to the code above?? Thanks! :) [b]Edit:[/b] It feels kind of hackish, but looking at the old code something like this might work: [code=csharp] else { DataTable results = 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"]; } } } } public static DataTable UserFind(int boardID,bool filter, [NotNull] string userName, [NotNull] string email, [NotNull] string displayName, [NotNull] object notificationType, [NotNull] object dailyDigest) { using (var cmd = DbHelpers.GetCommand("user_find")) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("BoardID", boardID); cmd.Parameters.AddWithValue("Filter", filter); cmd.Parameters.AddWithValue("UserName", userName); cmd.Parameters.AddWithValue("Email", email); cmd.Parameters.AddWithValue("DisplayName", displayName); cmd.Parameters.AddWithValue("NotificationType", notificationType); cmd.Parameters.AddWithValue("DailyDigest", dailyDigest); return LegacyDb.DbAccess.GetData(cmd); } }[/code] [b]Edit 2:[/b] Now that I look at it... what's the point of the else statement? Debugging?