asp.net – 经过身份验证时的umbraco公共访问错误

我在Umbraco 7中遇到了公共访问问题.

我使用自定义成员资格提供程序通过我的CRM数据库对用户进行身份验证.
我设置了一个规则,只允许访问经过身份验证的(前端)用户,并且我使用自定义角色提供程序来定义经过身份验证的用户具有访问者角色.如果未经过身份验证,则会将其重定向到登录页面.

当我调试网站时,用户具有以下角色:

我经过身份验证,当前用户的角色是好的.

但我仍然被重定向到登录页面!我不明白.

我的角色提供者:

public class CustomRoleProvider : Umbraco.Web.Security.Providers.MembersRoleProvider
{
    const int SITE_ID = 6;

    public override string ApplicationName
    {
        get
        {
            return "Site";
        }
    }

    public override string[] GetAllRoles()
    {
        return new[] { Const.VISITORS_LABEL };
    }

    public override string[] GetRolesForUser(string username)
    {
        return new[] { Const.VISITORS_LABEL };
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="username"></param>
    /// <param name="roleName"></param>
    /// <returns></returns>
    public override bool IsUserInRole(string username, string roleName)
    {
        //every user is a visitor
        if(roleName == Const.VISITORS_LABEL)
        {
            return true;
        }

        else
        {
            return base.IsUserInRole(username, roleName);
        }
    }

    public override string[] GetUsersInRole(string roleName)
    {
        if(roleName == Const.VISITORS_LABEL)
        {
            using (var db = new CRMEntities())
            {
                var usersEmails = db.Customer_View.Where(x => x.SiteID == SITE_ID).Select(x=>x.Email).ToArray();
                return usersEmails;
            }
        }
        else
        {
            return base.GetUsersInRole(roleName);
        }
    }
}

这是我用于身份验证的控制器:

public class MemberLoginSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
    // The MemberLogin Action returns the view, which we will create later. It also instantiates a new, empty model for our view:

    [HttpGet]
    [ActionName("MemberLogin")]
    public ActionResult MemberLoginGet()
    {
        return PartialView("MemberLogin", new MemberLoginModel());
    }

    // The MemberLogout Action signs out the user and redirects to the site home page:

    [HttpGet]
    public ActionResult MemberLogout()
    {
        Session.Clear();
        FormsAuthentication.SignOut();
        return Redirect("/");
    }

    // The MemberLoginPost Action checks the entered credentials using the standard Asp Net membership provider and redirects the user to the same page. Either as logged in, or with a message set in the TempData dictionary:
    [HttpPost]
    [ActionName("MemberLogin")]
    public ActionResult MemberLoginPost(MemberLoginModel model)
    {
        if (Membership.ValidateUser(model.Username, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);

            return RedirectToCurrentUmbracoPage();
        }

        else
        {
            TempData["Status"] = "Invalid username or password";
            return RedirectToCurrentUmbracoPage();
        }
    }
}

我的角色提供程序位于web.config中,并且Visitors角色在管理面板中被检测为角色.

<roleManager enabled="true" defaultProvider="CustomRoleProvider">
  <providers>
    <clear />
    <add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />
    <add name="CustomRoleProvider" type="*.UI.Helpers.CustomRoleProvider" />
  </providers>
</roleManager>

编辑:我忘了会员提供者:

 public class MyMembershipProvider : Umbraco.Web.Security.Providers.MembersMembershipProvider
{

const int SITE_ID = 6;
    //we dont let user change their password using RC website
    public override bool AllowManuallyChangingPassword
    {
        get
        {
            return false;
        }
    }

    public override bool EnablePasswordReset
    {
        get
        {
            return false;
        }
    }

    public override bool EnablePasswordRetrieval
    {
        get
        {
            return false;
        }
    }

    public override bool ValidateUser(string username, string password)
    {
        Customer_View user;

        //just to avoid errors with uppercase letters
        username = username.ToLowerInvariant();

        using (var db = new CRMEntities())
        {
            user = db.Customer_View.SingleOrDefault(x => x.Email == username && x.SiteID == SITE_ID);

            //no user with this email
            if (user == null)
                return false;

            //check if password is same
            return user.Password == password;
        }
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        //just to avoid errors with uppercase letters
        username = username.ToLowerInvariant();
        MembershipUser toReturn;

        using (var db = new CRMEntities())
        {
            Customer_View user = db.Customer_View.SingleOrDefault(x => x.Email == username && x.SiteID == SITE_ID);

            toReturn = user != null ? new MembershipUser(
                //provider name
                "MyMembershipProvider", string.Format("{0} {1}", user.FirstName, user.LastName),
                username, username, string.Empty, string.Empty, true, true, user.CreateDate, new DateTime(), new DateTime(), new DateTime(), new DateTime()) :

                null;

        }

        return toReturn;
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        return this.GetUser(providerUserKey as string, userIsOnline);
    }


}

每当我尝试访问具有特定访问权限的页面时,即使我通过身份验证,我也会被重定向到登录页面:

我该如何解决?

最佳答案 为什么要添加自定义角色提供程序.保持简单.如果您有该站点的注册页面,则可以以编程方式分配成员类型和成员角色

如果您从后端添加成员,则可以轻松添加“访问者”角色.

因此,在这两种情况下,“访问者”角色都可以轻松应用于所有成员,并且您可以轻松地保持页面登录访问者角色(所有经过身份验证的身份).

编辑:
我已经删除了以编程方式向用户添加角色的代码,因为您不需要,解决方案如下:

正如您所知,自定义角色提供程序和自定义成员资格提供程序齐头并进.您已添加自定义成员资格提供程序并覆盖了ValidateUser方法,但为了使所有这些工作,您需要覆盖另外两个GetUser方法请参阅下面的自定义提供程序代码,它可以工作

的MembershipProvider

public class MyMembershipProvider : MembersMembershipProvider
{
    public override bool ValidateUser(string username, string password)
    {
        if (base.ValidateUser(username,password))
        {
            //if this is umbraco user validate by base method
            return true;
        }
        else
        {
            var allow = //add your validation code for CRM, I have checked if username is "tester" and allowed for testing purpose.
            return allow;
        }
    }
    // These two methods below which you have not overridden and need to override for public access to work

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        if(base.GetUser(providerUserKey, false)!=null)
            //if this is umbraco user add it as is.
            return base.GetUser(providerUserKey,userIsOnline);
        else
            //Add your CRM user, I do not have database, so added test user
            return new MembershipUser("UmbracoMembershipProvider", "tester", 1233, "tester@test.com", null, null, true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
    }
    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        if (true)//check if this is CRM user here
        {
            return new MembershipUser("UmbracoMembershipProvider", "tester", 1233, "tester@test.com", null, null, true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
            //I am adding test user, you should create user from your CRM database
        }
        else
            return base.GetUser(username,false);

    }

}

EDIT2

好的,我调试了roleprovider和membershipprovider中的每一段代码,当用户登录用户试图访问受保护页面时,首先调用GetUser(字符串用户名,bool userIsOnline),如果失败,则返回登录页面,此后成功GetUser(object providerUserKey,bool userIsOnline)接到一个电话.如果返回null,则显示访问页面不足,否则将调用GetRolesForUser(字符串用户名).并显示所有成功页面.我在两个文件的每个方法上都设置了断点,因此只涉及这3种方法.当你看到登录页面时,我的猜测是GetUser(字符串用户名,bool userIsOnline)这个第一次调用失败了.

以下是我的文件,如果它有帮助

角色配置部分

<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
  <providers>
    <clear />
    <!--<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />-->
    <add name="UmbracoRoleProvider" type="Assembly.Providers.MyRolesProvider" />
  </providers>
</roleManager>

会员配置部分

<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
  <providers>
    <clear />
    <add name="UmbracoMembershipProvider" type="Assembly.Providers.MyMemberShipProvider, Assembly" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" />
    <!--<add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />-->
    <add name="UsersMembershipProvider" type="Assembly.Providers.MyUserMembershipProvider, Assembly" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
  </providers>
</membership>

的AccountController

public class AccountSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
    [HttpPost]
    public ActionResult LoginForm(LoginModel model)
    {
        //model not valid, do not save, but return current umbraco page
        if (!ModelState.IsValid)
        {
            //Perhaps you might want to add a custom message to the TempData or ViewBag
            //which will be available on the View when it renders (since we're not 
            //redirecting)          
            return CurrentUmbracoPage();
        }

        // Login
        if (Membership.ValidateUser(model.Username, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.Username, false);
            return RedirectToCurrentUmbracoUrl();
        }
        else
        {
            ModelState.AddModelError("Username", "Username is not valid");
            return CurrentUmbracoPage();
        }
    }
}

public class LoginModel
{
    [Required]
    public string Username { get; set; }

    [Required]
    [DataType(DataType.Password)] 
    public string Password { get; set; }
}

RolesProvider

public class MyRolesProvider : MembersRoleProvider
{
    const string VISITORS_LABEL = "Visitor";

    public override string[] GetAllRoles()
    {
        var roles = base.GetAllRoles().ToList();
        roles.Add(VISITORS_LABEL);
        return roles.ToArray();
    }
    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        if(roleName== VISITORS_LABEL)
        {
            var users = ApplicationContext.Current.Services.MemberService
                .GetAllMembers().Select(m => m.Email).ToList();
            users.Add("tester@test.com");
            return users.ToArray();
        }
        return base.FindUsersInRole(roleName, usernameToMatch);
    }
    public override bool RoleExists(string roleName)
    {
        if(roleName == VISITORS_LABEL)
        {
            return true;
        }
        return base.RoleExists(roleName);
    }
    public override string[] GetRolesForUser(string username)
    {
        var roles = base.GetRolesForUser(username).ToList();
        roles.Add(VISITORS_LABEL);
        return roles.ToArray();
    }
    public override bool IsUserInRole(string username, string roleName)
    {
        if(roleName == VISITORS_LABEL)
        {
            return true;
        }
        return base.IsUserInRole(username, roleName);
    }
    public override string[] GetUsersInRole(string roleName)
    {
        if(roleName == VISITORS_LABEL)
        {
            var list = ApplicationContext.Current.Services.MemberService
                .GetAllMembers().Select(m => m.Email).ToList();
                list.Add("tester@test.com");
            return list.ToArray();
        }
        return base.GetUsersInRole(roleName);
    }
}

EDIT3:

我重现了你的场景,它与web.config配置有关

当我保持web配置为会员资格时,除非我打电话,否则它没有打到我的提供商

<membership defaultProvider="MyMembershipProvider" userIsOnlineTimeWindow="15">
  <providers>
    <clear />
    <add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" />
    <add name="MyMembershipProvider" type="Umbraco724.Providers.MyMembersMembershipProvider, Umbraco724" />
    <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
  </providers>
</membership>

但是当它改变为如下所示它起作用.请仔细检查配置的差异.

<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
  <providers>
    <clear />
    <add name="UmbracoMembershipProvider" type="Umbraco724.Providers.MyMembersMembershipProvider, Umbraco724"  minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Visitor" passwordFormat="Hashed" />
    <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
  </providers>
</membership>

我认为umbraco只为会员和用户提供一个提供商.此外,它的名字应该只是UmbracoMembershipProvider.当我保持不同然后也有错误.

点赞