Umbraco 7自定义会员和角色提供程序

5

我查看了数十份文档,确定正在执行正确的操作,但肯定是有一些小细节我遗漏了。

我想使用自己的登录机制登录我的网站。登录机制位于Identity Server中,用于单点登录。

但我想使用Umbraco的公共访问功能,因此我正在通过更改配置文件来添加来自本地数据库的角色。

<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
      <providers>
        <clear />
        <add name="UmbracoRoleProvider" type="rcsedWebServiceBLL.RCSEdRoleProvider" />
      </providers>
    </roleManager>

并且实现RoleProvider

 class RCSEdRoleProvider : RoleProvider
    {
        private string _ApplicationName = "UmbracoRoleProvider";
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
        throw new NotImplementedException();
    }

    public override string ApplicationName
    {
        get { return _ApplicationName; }
        set
        {
            if(string.IsNullOrEmpty(value))
                throw new ProviderException("ApplicationName Cacnnot be Empty");

            if(value.Length > 0x100)
                throw new ProviderException("provider application name too long");

            _ApplicationName = value;
        }
    }

    public override void CreateRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        throw new NotImplementedException();
    }

    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        throw new NotImplementedException();
    }

    public override string[] GetAllRoles()
    {
        return UBISRoles.GetRoleList();
    }

    public override string[] GetRolesForUser(string username)
    {
        // code to return user role access
        try
        {
           //ool isAuthenticateSession = RCSEd.UolsSecurity.CommonFunctions.CheckAuthenticateSessionOrNot();

            if (HttpContext.Current.Session["UOSStudent"] != null)
            {
                return (String[])HttpContext.Current.Session["userRoles"];
            }
            else
            {
                List<String> retval = new List<string>();
                retval.Add("Public");
                return retval.ToArray();
            }
        }
        catch (Exception ex)
        {
           // AppLogWriter _objApplog = new AppLogWriter();
           // _objApplog.WriteLogMessages(ex.Message.ToString());
            //TODO catch Error 
            List<String> retval = new List<string>();
            retval.Add("Public");
            return retval.ToArray();
        }

    }

    public override string[] GetUsersInRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        try
        {
            foreach (String role in (String[])HttpContext.Current.Session["userRoles"])
            {
                if (String.Compare(role, roleName, true) == 0)
                    return true;
            }


            return false;

        }
        catch { }

        return false;

    }

    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    public override bool RoleExists(string roleName)
    {

        foreach (string val in UBISRoles.GetRoleList())
        {
            if (val == roleName)
                return true;
        }

        return false;
    }
}

class UBISRoles
{
    private static string[] allroles = new string[] { //"Public", 
     "MembershipCandidate",
        "MembershipMember"
      };


    public static string[] GetRoleList()
    {
        return allroles;
    }



    public static void SetRoles(DataTable UBIsRolesResultsTBL)
    {
        List<String> userRoles = new List<string>();

        DataRow rec = UBIsRolesResultsTBL.Rows[0];


        switch (rec["Membership"].ToString())
        {

            case "member":
                userRoles.Add("MembershipMember");
                break;
            case "pending member":
                userRoles.Add("MembershipPending");//add
                break;
            case "public":
                userRoles.Add("MembershipPublic");//add
                break;

        }






        HttpContext.Current.Session["userRoles"] = userRoles.ToArray();

    }

    private static void CheckSimpleFieldVal(List<String> userRoles, DataRow rec, string roleName)
    {
        try
        {
            if (string.Compare(rec[roleName].ToString(), "YES", true) == 0)
                userRoles.Add(roleName);

        }
        catch (Exception ex)
        {
            string msg = ex.Message;

        }

    }

    private static void CheckSimpleFieldValV2(List<String> userRoles, DataRow rec, string roleName)
    {
        try
        {
            if (string.Compare(rec[roleName].ToString(), "1", true) == 0)
                userRoles.Add(roleName);

        }
        catch (Exception ex)
        {
            string msg = ex.Message;

        }

    }

}

这样做很好,一切都被加载到umbraco后台的成员组中。

但是,当我尝试实现MembershipProvider时,感觉有些问题。Web配置文件如下:

  <membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add name="UmbracoMembershipProvider" type="rcsedWebServiceBLL.RCSEdMembershipProvide"  />
        <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>

而Membershiprovider类看起来像这样:
class RCSEdMembershipProvide : MembershipProvider
    {
        string connectionStringName;
        private string _ApplicationName =  "UmbracoMembershipProvider";
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
        base.Initialize(name, config);

      /*  if (config["ConnectionStringName"] != null)
            connectionStringName = config["connectionStringName"];*/




    }

    public override string ApplicationName
    {
        get { return _ApplicationName; }
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ProviderException("ApplicationName Cacnnot be Empty");

            if (value.Length > 0x100)
                throw new ProviderException("provider application name too long");

            _ApplicationName = value;
        }
    }

    public override bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        throw new NotImplementedException();
    }

    public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
    {
        throw new NotImplementedException();
    }

    public override bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        throw new NotImplementedException();
    }

    public override bool EnablePasswordReset
    {
        get { throw new NotImplementedException(); }
    }

    public override bool EnablePasswordRetrieval
    {
        get { throw new NotImplementedException(); }
    }

    public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override int GetNumberOfUsersOnline()
    {
        throw new NotImplementedException();
    }

    public override string GetPassword(string username, string answer)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        try
        {
            User user = (User)HttpContext.Current.Session["user"];
            if (user != null)
                return new MembershipUser("RCSEdMembershipProvider", user.DisplayName, username, user.Email, "", "", true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
            else
                return null;

        }
        catch
        {
            return null;
        }
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        try
        {
            User user = (User)HttpContext.Current.Session["user"];

            if (user != null)
                return new MembershipUser("RCSEdMembershipProvider", user.DisplayName, providerUserKey, user.Email, "", "", true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
            else
                return null;
        }
        catch
        {

            return null;
        }
    }

    public override string GetUserNameByEmail(string email)
    {
        throw new NotImplementedException();
    }

    public override int MaxInvalidPasswordAttempts
    {
        get { throw new NotImplementedException(); }
    }

    public override int MinRequiredNonAlphanumericCharacters
    {
        get { throw new NotImplementedException(); }
    }

    public override int MinRequiredPasswordLength
    {
        get { throw new NotImplementedException(); }
    }

    public override int PasswordAttemptWindow
    {
        get { throw new NotImplementedException(); }
    }

    public override MembershipPasswordFormat PasswordFormat
    {
        get { throw new NotImplementedException(); }
    }

    public override string PasswordStrengthRegularExpression
    {
        get { throw new NotImplementedException(); }
    }

    public override bool RequiresQuestionAndAnswer
    {
        get { throw new NotImplementedException(); }
    }

    public override bool RequiresUniqueEmail
    {
        get { throw new NotImplementedException(); }
    }

    public override string ResetPassword(string username, string answer)
    {
        throw new NotImplementedException();
    }

    public override bool UnlockUser(string userName)
    {
        throw new NotImplementedException();
    }

    public override void UpdateUser(MembershipUser user)
    {
        throw new NotImplementedException();
    }

    public override bool ValidateUser(string username, string password)
    {


        return true;
    }
}

我一直将validateUser设置为true。

因此,当用户登录到我的身份服务器时,我在HttpContext.Current.Session["userRoles"]中加载用户角色,并限制页面的公共访问,并将用户重定向到正确的页面。

当用户未登录时,会被重定向到登录页面,这很好,但是当用户返回并加载他/她的角色并尝试访问受限页面时,成员资格提供程序ValidateUser不起作用,用户会一次又一次地被重定向回登录页面。

PS. 我正在使用umbraco 7.1.3

请原谅我的冗长问题,但我想涵盖所有步骤。谢谢您的帮助。


你的登录界面是什么样子的? - Davor Zlotrg
你能解释一下你的意思吗?它看起来像什么?它只是一个普通的登录页面。但正如我上面提到的,它设置在不同的项目中,因为它是单点登录架构。 - dori naji
1个回答

1

无法评论,所以我会回答 :) 希望这会有所帮助。我的示例基于用户使用umbraco登录,您希望外部提供程序处理成员资格登录。如果情况相反,我很抱歉。

我在umbraco 7.2中拥有角色提供程序和用户提供程序,希望您可以使用我的实现进行比较。 这对我有用。

Web.config如下:

<membership defaultProvider="UmbracoMembershipProvider" 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="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed"/>
        <add name="UmbracoMembershipProvider" type="XXX.Model.Membership.SAPMembershipProvider" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="_umbracoSystemDefaultProtectType" passwordFormat="Hashed"/>
      </providers>
    </membership>
    <!-- Role Provider -->
    <roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
      <providers>
        <clear/>
        <add name="UmbracoRoleProvider" type="XXX.Model.Membership.SAPRoleProvider"/>
        <!--<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider"/>-->
      </providers>
    </roleManager>

我的角色提供程序看起来像这样:
    public class SAPRoleProvider : Umbraco.Web.Security.Providers.MembersRoleProvider
        {

            public override bool IsUserInRole(string username, string roleName)
            {
                if (roleName.ToLower() == "standard")
                    return true;
                else
                    return base.IsUserInRole(username, roleName);
            }
            public override string[] GetRolesForUser(string username)
            {
                return new[] { "Standard" };
            }
        }

和成员提供程序类似于这样:

public class SAPMembershipProvider : Umbraco.Web.Security.Providers.UsersMembershipProvider
    {
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ChangePassword(oldPassword, newPassword, username);
        }
        public override string ResetPassword(string username, string answer)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ResetPassword(username).ToString();
        }
        public override MembershipUser GetUser(object providerUserKey, bool someonelinestuff)
        {
            return GetSapUser(providerUserKey);
        }


        /// <summary>
        /// It is not the username but providerUserKey i ask for herem just to test since I am not sure what SAP want right now, regarding request of userdata
        /// </summary>
        /// <param name="providerUserKey"></param>
        /// <param name="someonelinestuff"></param>
        /// <returns></returns>
        public override MembershipUser GetUser(string username, bool someonelinestuff)
        {
            return GetSapUser(username);
        }
        public SAPMembershipUser GetUser(string username)
        {
            return (SAPMembershipUser)GetUser(username, false);
        }

        public override bool ValidateUser(string username, string password)
        {
            try
            {
                ILoginService LoginS = new LoginService();
                SAPMembershipUser SU = LoginS.Login(username, password);
                if (SU != null)
                {
                    FrieLib.CacheHelper.StoreCache(username.ToLower(), SU,true,20);
                    return true;
                }
            }
            catch { return false; }
            return false;
        }


        protected override bool PerformChangePassword(string username, string oldPassword, string newPassword)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ChangePassword(oldPassword, newPassword, username);
        }
        private SAPMembershipUser GetSapUser(string username)
        {

            try
            {
                SAPMembershipUser SU = (SAPMembershipUser)FrieLib.CacheHelper.RetrieveCache(username.ToLower());
                if (SU != null)
                {
                    return SU;
                }
                else
                {
                    HttpContext.Current.Response.Redirect("/umbraco/Surface/MemberLoginSurface/MemberLogout");
                }

            }
            catch (Exception es)
            {
                HttpContext.Current.Response.Redirect("/umbraco/Surface/MemberLoginSurface/MemberLogout");
            }
            return null;
        }
        private SAPMembershipUser GetSapUser(object providerUserKey)
        {
            return GetSapUser(providerUserKey.ToString());
        }
    }

我有一个额外的步骤,不确定你是否遗漏了,我会确保最终用户已经登录。

[HttpPost]
        [ActionName("MemberLogin")]
        public ActionResult MemberLoginPost(MemberLoginModel model)
        {
            if (Membership.ValidateUser(model.Username, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.Username.ToLower(), model.RememberMe);

                    return RedirectToCurrentUmbracoUrl();
            }
            else
            {
                TempData["Status"] = "danger";
                TempData["StatusMessage"] = "login_fail_message";
                return RedirectToCurrentUmbracoPage();
            }
        }

我希望它能够帮到你。


嗨Lau,谢谢你的回答,我有一个类似的实现,但为了理解你的情况,如果用户登录,您是检查用户名和密码是否与您自己的数据库匹配,而不是Umbraco吗? - dori naji
是的,用户存储在SAP中,所以它是一个外部系统。 SAPMembershipUser只是从System.Web.Security.MembershipUser继承而来。我的想法是,也许你忘记了FormsAuthentication.SetAuthCookie,或者你对ApplicationName或initialize的实现是不必要的。这只是一个想法。你应该能够使用我写的内容,将SAPMembershipUser SU = LoginS.Login(username, password);替换为你自己的代码... FrieLib.CacheHelper.StoreCache(username.ToLower(), SU,true,20);意味着我在服务器上缓存了用户,这样我就可以在GetSapUser中再次获取到他。 - Lau Frie
我明白了,我也注意到你正在实现Umbraco.Web.Security.Providers.MembersRoleProvider,但是我正在实现asp.net membershipprovider。你觉得这是问题所在吗? 附注:我正在我的登录中设置authcookie。 - dori naji
抱歉,我忘了在我的示例中提到我在Umbraco中创建了一个名为“standard”的角色。然后我使用该角色保护页面。因此,我的示例角色提供程序会询问isuserinrole。因此,这些角色实际上并不来自外部系统。您可以将它们与外部数据库一对一匹配。我讲得通吗? - Lau Frie
这样说确实有道理,但是我的意思是你正在使用Umbraco.Web.Security.Providers.UsersMembershipProvider,而我正在使用membershiprovider,并且我无法使用UsersMembershipProvider,因为它要求我将umbraco更新到一个新版本,这是我目前无法做到的。所以如果您像这样实现public class SAPMembershipProvider : MembershipProvider而不是SAPMembershipProvider : Umbraco.Web.Security.Providers.UsersMembershipProvider,是否仍然有效? - dori naji
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接