身份验证时出现 umbraco 公共访问错误

2024-03-20

我在 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 中,并且访客角色在管理面板中被检测为角色。

<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>

EDIT:我忘记了会员提供商:

 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);
    }


}

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

我该如何解决它?


为什么要添加自定义角色提供者。只要保持简单即可。如果您有该网站的注册页面,您可以通过编程方式分配成员类型和成员角色

如果您从后端添加会员,您可以轻松添加“访客”角色。

因此,在这两种情况下,“访客”角色都可以轻松应用于所有成员,并且您可以轻松地将页面保留为访客角色登录(所有身份验证)。

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

如您所知,自定义角色提供程序和自定义会员资格提供程序是齐头并进的。您已添加自定义会员资格提供商并覆盖ValidateUser方法,但要使这一切起作用,您需要重写另外两个方法GetUser请参阅下面的自定义提供程序的代码,它会起作用

会员提供者

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, "[email protected] /cdn-cgi/l/email-protection", 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, "[email protected] /cdn-cgi/l/email-protection", 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(string username, bool userIsOnline)被调用,如果失败,返回登录页面,成功后GetUser(object providerUserKey, bool userIsOnline)接到电话。如果返回 null,则显示访问不足页面GetRolesForUser(string username)被叫。并显示所有成功页面。我在两个文件的每个方法上都设置了断点,所以只涉及这3个方法。正如你看到的登录页面,我的猜测是GetUser(string username, 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>

账户控制器

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; }
}

角色提供者

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("[email protected] /cdn-cgi/l/email-protection");
            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("[email protected] /cdn-cgi/l/email-protection");
            return list.ToArray();
        }
        return base.GetUsersInRole(roleName);
    }
}

EDIT3:

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

当我按如下方式保留会员资格的网络配置时,除非我致电,否则它不会影响我的提供商

<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 只为会员和用户提供一个提供商。也当它的名字应该是Umbraco会员提供商仅有的。当我保持不同时,也会出现错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

身份验证时出现 umbraco 公共访问错误 的相关文章

随机推荐

  • 在延迟表达式求值中,R Shiny 使用变量的更改值

    这是问题的简单演示 library shiny ui lt fluidPage textOutput Text1 textOutput Text2 server lt function input output for i in 1 2 i
  • 如何将 Nest.js 微服务拆分为单独的项目?

    假设我想创建一个简单的影院管理平台 它需要很少的微服务 movies cinemas payments etc 你会如何在 Nest js 中做到这一点 我不希望它们位于同一个大文件夹中 因为这感觉就像制作一个整体 我希望它们成为单独的 N
  • 无法包含 Microsoft.Security.Application?

    我不能包括微软 安全 应用程序 using Microsoft Security Application 给出这个错误 命名空间 Microsoft 中不存在类型或命名空间名称 Security 是否缺少程序集引用 是的 我点击了Bin g
  • Java 序列化库,无需无参数构造函数和 Serialized 实现

    java世界中是否有任何方法可以在不需要无参数构造函数和Serialized实现的情况下进行序列化 Look at XStream http xstream codehaus org JSX http jsx org or 谷歌协议缓冲区
  • AMF消息结构?

    Adobe s AMF 格式的文档 http opensource adobe com wiki download attachments 1114283 amf3 spec 05 05 08 pdf似乎并没有实际指定整个 AMF 消息的结
  • 连接4条信息并保存

    保存 编辑和加载信息 我想要加载的信息是我自己添加的 每行信息将包含 4 条信息 字符串 整数 字符串 整数 通过 4 个单独的编辑框和一个按钮 我会将这些信息添加到 数据库 中 不确定我是否需要数据库 或者是否可以通过 Tstringli
  • 无法使用 Robo3T 连接到 Mongo 副本集

    我在使用 RoboMongo 连接到 Mongo 集群时遇到问题 当我在指南针中使用相同的连接字符串时 它可以工作 但 Compass 社区版不像 Robomongo 那样灵活 无法连接到副本集 Employee UAT hhds6666
  • PHP DateTime::createFromFormat 返回错误的日期

    当尝试跑步时createFromFormat使用太平洋 奥克兰时区和格式字符串 F Y 尽管我提供了 2019 年 9 月 但返回的日期是 10 月 1 日 我尝试在 CLI 和 FPM 中的 PHP 7 3 9 和 7 2 22 上运行它
  • 为什么 WPF 吞咽 Window.Activated 的事件处理程序中引发的异常?

    简单的 WPF 应用程序 带有简单 空的内容Window其中我将事件处理程序连接到窗口Activated event public partial class MainWindow public MainWindow InitializeC
  • 如何从 Nexus 存储库请求工件的大小?

    我知道 Nexus 支持 REST 请求 您能告诉我如何根据 Nexus 从存储库请求某些工件的大小吗 谢谢 您有以下选项 使用工件内容 URI 的完整路径并添加参数describe info 例如 https repository son
  • 如何将要渲染的任意窗口重定向到内存中的后缓冲区?

    我正在尝试一个自行开发的应用程序托管框架 并且我想抽象输入 输出 以便我可以优雅地处理崩溃 Chrome 使用非常相似的模型 有什么方法可以获取任意窗口句柄 并说服它开始渲染到后缓冲区吗 或者我应该首先创建自己的窗口 然后将客户端应用程序重
  • 如何告诉 TypeScript 接口 T 比具有索引签名的类型 U 窄?

    我有一个函数可以验证 JSON 响应以确保它对应于给定的形状 以下是我的类型 定义了所有可能的 JSON 值 取自https github com microsoft TypeScript issues 1897 issuecomment
  • 如何更改操作栏上的文本

    目前它只显示应用程序的名称 我希望它显示自定义的内容并且对于我的应用程序中的每个屏幕都不同 例如 我的主屏幕可以在操作栏中显示 page1 而应用程序切换到的另一个活动可以在该屏幕操作栏中显示 page2 更新 最新的 ActionBar
  • Android 应用程序中的 VideoView 全屏

    我的应用程序中有一个视频视图 代码是这样的
  • 加载时将 Google 地图信息窗口居中

    我在将 InfoWindow 集中在页面加载时遇到问题 加载时 地图以标记为中心 这使 InfoWindow 离开屏幕 我正在使用地图容器的较短高度 现在 单击标记确实会将地图重新 置于信息窗口的中心 使其看起来与我想要的一模一样 在这种情
  • 访问其他层中的对象(cocos2d)

    我正在用操纵杆在一层中移动精灵 现在 根据最佳实践 操纵杆和精灵必须位于同一场景的不同层中 我已经设法将它们分开 但我现在完全陷入困境 完全不知道如何将操纵杆命令从一层传递到另一层 推荐的方法是什么 Scene Game Play Laye
  • 图像中的隐形水印[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 JavaFX 8 中管理多线程的最佳方法是什么?

    我正在尝试找到一种有效的方法来影响 JavaFX GUI 元素的形状和内容 例如简单的Pane 使用多线程 假设我有一个简单的Pane 我在其上显示已填充Circle在给定的时间间隔内 我希望有可能回答它们 例如通过按相应的键 到目前为止
  • 向 Jira 的 api 添加附件

    我正在尝试使用他们的 API 将文件附加到 Jira 案例 我在 Drupal 6 PHP v 5 0 中执行此操作 这是我的代码 ch curl init header array Content Type multipart form
  • 身份验证时出现 umbraco 公共访问错误

    我在 Umbraco 7 中的公共访问方面遇到问题 我使用自定义会员资格提供商通过 CRM 数据库对用户进行身份验证 我设置了一条规则来允许访问仅经过身份验证的 前端 用户我使用自定义角色提供程序来定义经过身份验证的用户具有访客角色 如果未