专栏首页木宛城主SharePoint 2013自定义Providers在基于表单的身份验证(Forms-Based-Authentication)中的应用

SharePoint 2013自定义Providers在基于表单的身份验证(Forms-Based-Authentication)中的应用

由于项目的需要,登录SharePoint Application的用户将从一个统一平台中获取,而不是从Domain中获取,所以需要对SharePoint Application的身份验证(Claims Authentication Types)进行更改,即采用更加灵活的混合模式登录:Windows Authentication和Forms Based Authentication。故本篇博客将着重笔墨去介绍SharePoint 2013自定义Providers在基于表单的身份验(Forms-Based-Authentication)中的应用。

更改身份验证

首先需要了解的一点事,怎样去更改指定的Web Application 的身份验证。进入SharePoint 2013 Central Administration-àApplication Management-àManage Web Applications-àAuthentication Providers,即如下所示:

如截图所示那样,启用了FBA之后,需要我们提供自定义的Menbership Provider和Role Provider。

创建Membership Provider和Role Provider

这儿我选择创建一个Class Library,当然你也可以直接创建一个SharePoint 2013 Empty Project,注意不管是哪种,最终都需要把Assembly 注册/安装 到GAC里

  • 如果是创建了SharePoint Project,要安装Assembly到GAC,直接部署就行。
  • 如果是创建了Class Library,需要有两个步骤1).Sign the assembly(右键项目-àProperty-àSigning),2)gacutil /i "<assembly path/assembly name.dll>",如下所示(使用VS Command Tool):

获取Strong Name Key File

安装Assembly到GAC

对于.NET 4.0以上的Assembly,GAC位于C:\Windows\Microsoft.NET\assembly。.NET 3.5 GAC在C:\Windows\assembly,所以别找错地方。Assembly成功注册到GAC后,最好IISReset下。

接着,创建相关的Provider,分别继承MembershipProvider和RoleProvider即可。

  • 自定义MembershipProvider,主要代码如下:
public class FBA_CustomRoleProvider : MembershipProvider
    {
        #region 重写的方法

        private MembershipUserCollection employees;
        private void generateUsers()
        {

            employees = new MembershipUserCollection();
            employees.Add(new MembershipUser(this.Name, "Jack Chen", "JackChen", "Jack@Chen.com", "What your Name?", "I am Jack", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));
            employees.Add(new MembershipUser(this.Name, "Bruce Li", "BruceLi", "BruceLi@Li.com", "How are u?", "How old are u", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));
            employees.Add(new MembershipUser(this.Name, "Eyes Wang", "EyesWang", "EyesWang@Mintcode.com", "What the hell?", "what the fuck", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            if (employees == null) generateUsers();
            MembershipUserCollection returnFoundUsers = new MembershipUserCollection();

            (employees.Cast<MembershipUser>().

                Where(membershipUser => membershipUser.UserName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())))

                .ToList().ForEach(returnFoundUsers.Add);

            totalRecords = returnFoundUsers.Count;
            return returnFoundUsers;
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {

            if (employees == null) generateUsers();
            totalRecords = employees.Count;
            return employees;
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {

            if (employees == null) generateUsers();
            IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);
            return usersFound.FirstOrDefault();
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {

            if (employees == null) generateUsers();

            IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.ProviderUserKey.ToString() == providerUserKey.ToString());

            return usersFound.FirstOrDefault();
        }

        public override string GetUserNameByEmail(string email)
        {
            if (employees == null) generateUsers();

            IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.Email.ToLowerInvariant() == email.ToLowerInvariant());

            MembershipUser user = usersFound.FirstOrDefault();


            if (user != null)

                return user.UserName;

            else

                return null;
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {

            if (employees == null) generateUsers();
            MembershipUserCollection returnFoundUsers = new MembershipUserCollection();

            (employees.Cast<MembershipUser>().

             Where(membershipUser => membershipUser.Email.ToLowerInvariant().Contains(emailToMatch.ToLowerInvariant())))

                .ToList().ForEach(returnFoundUsers.Add);

            totalRecords = returnFoundUsers.Count;

            return returnFoundUsers;

        }

        public override bool ValidateUser(string username, string password)
        {
            //return true;
            if (employees == null) generateUsers();

            IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);
            MembershipUser user = usersFound.FirstOrDefault();

            if (user != null)
            {

                if (string.IsNullOrEmpty(password))
                {

                    return false;

                }

                else
                {

                    return true;

                }

            }

            else

                return false;
        }
        #endregion
}
  • 自定义Role Provider,如下所示:
public class FBA_CustomMembershipProvider:RoleProvider
    {
       public override string ApplicationName { get; set; }

        //所有角色
        private string[] m_AllRoles = { "Developer", "Administrator", "Designer", "Architect ", "UI" };
    
        private string[,] m_RolesForUser = new string[,] {

            {"Eyes Wang", "Developer"},

            {"Bruce Li","Administrator"},

            {"Jack Chen","Designer,Architect"},

        };
                
        /// <summary>
        /// 获取全部角色
        /// </summary>
        /// <returns></returns>
        public override string[] GetAllRoles()
        {

            return m_AllRoles;

        }
        
        /// <summary>
        /// 根据User得到其相关的角色
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public override string[] GetRolesForUser(string username)

        {
            List<string> roles = new List<string>();
            for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)
            {

                if (m_RolesForUser[i, 0] == username)
                {
                    roles = m_RolesForUser[i, 1].Split(',').ToList<string>();
                }

            }
            return roles.ToArray();
        }

            /// <summary>
            /// 根据角色获取其绑定的用户
            /// </summary>
            /// <param name="rolename"></param>
            /// <returns></returns>
          public override string[] GetUsersInRole(string rolename)
          {

              List<string> users = new List<string>();
              for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)
               {
                   List<string> userRoles = m_RolesForUser[i, 1].Split(',').ToList<string>();
                   if (userRoles.Where(userRole => userRole == rolename).Count() > 0)
                  {

                     users.Add(m_RolesForUser[i, 0]);
                  }

              }
              return users.ToArray();
           }


         public override bool IsUserInRole(string username, string rolename)
         {

              List<string> usersForRole = GetUsersInRole(rolename).ToList();
              if (usersForRole.Where(userName => userName == username).Count() > 0)
              {
                  return true;
              }

              else
              {
                  return false;
              }

         }

        public override bool RoleExists(string rolename)
        {

             bool roleExsists = m_AllRoles.ToList().Where(roleName => roleName == rolename).Count() > 0;
             return roleExsists;
        }

        public override string[] FindUsersInRole(string rolename, string usernameToMatch)
        {

            List<string> users = GetUsersInRole(rolename).ToList<string>();
            List<string> foundUsers = users.Where(userName => userName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())).ToList<string>();
            return foundUsers.ToArray();
       }}
  • 自定义的Provider成功安装到GAC之后,接着修改web.config。注意需要修改3个地方,Web Application Config、SharePoint Central Administration Config、SecurityTokenServiceApplication,其路径如果记不住的话,打开IIS,浏览即可,即如下所示:

修改Web Config

Web Config需要Assembly的Public Key Token,可以使用VS Command Tool来获取:

  • 首先修改Web Application的Web Config,找到其Membership节点,将以下代码复制进:
 <membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomMembershipProvider" type="Eyes.CustomProvider.FBA_CustomRoleProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </membership>
    <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
      <providers>
        <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomRoleProvider" type="Eyes.CustomProvider.FBA_CustomMembershipProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </roleManager>
  • 接着修改SharePoint Central Administration的Web Config,
<membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomMembershipProvider" type="Eyes.CustomProvider.FBA_CustomRoleProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </membership>
    <roleManager>
      <providers>
        <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomRoleProvider" type="Eyes.CustomProvider.FBA_CustomMembershipProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </roleManager>
  • 然后修改SecurityTokenSeriveApplication的Web Config,
<system.web>
     <membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomMembershipProvider" type="Eyes.CustomProvider.FBA_CustomRoleProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </membership>
    <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
      <providers>
        <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="CustomRoleProvider" type="Eyes.CustomProvider.FBA_CustomMembershipProvider,Eyes.CustomProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4a0ffa664cbc06c" />
      </providers>
    </roleManager>
  </system.web>
  • 最后将Web Application的Authentication Type修改为混合模式,如下所示

分配用户并测试

成功为Web Application创建了自定义的Provider之后,接着就是测试是否成功。如添加访问用户,可以如下图操作所示:

搜索用户,如下图所示:

访问Site,提示混合登录模式,如下图所示:

登录成功后显示信息:

小结

当以Windows Authentication注销时,会发生错误(查阅日志后报错信息encodeValue不能为空)。我猜是没清理Session,查了很多资料,发现这是个别现象。不知道最新的SharePoint 2013 Updates有没有解决这个问题。我的版本是SharePoint 2013 Server(原始版本,从未更新过)。如果解决的话,劳烦各位朋友告诉我一下。点击代码下载

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SharePoint Farm 3-Tier拓扑结构的实施解决方案

    难得的假期,难得有时间来梳理知识。 我写过很多关于SharePoint的安装和配置,有利用PowerShell的,也有图形安装界面的。 也演示了怎样创建一...

    用户1161731
  • 探索MVP(Model-View-Presenter)设计模式在SharePoint平台下的实现

    对于SharePoint Developers来说,往往会过多的去关注SharePoint平台和工具,而把设计模式和代码的可测试性放在了一个较低的优先级。这并...

    用户1161731
  • 修复SharePoint 2013 Search 拓扑错误

    Problem 当创建和配置SharePoint 2013 Search Service Application成功之后,进入详细配置页后,在Search Ap...

    用户1161731
  • Set解决重复数据问题

    HashSet实现set接口,实际上是由hashMap实现的,所以不保证遍历顺序,并且允许使用null,时间复杂度和hashMap一样,为O(1),不超过O(n...

    HaC
  • 让web api 4.5支持Jquery.getJson(url,handle)跨域访问

    代码片段,google了半天,找到的都是4.5 rc,或之前版本的代码,发现都不能用,正式版后有些方法做了修改。我重新修改一下分享给大家 public stat...

    阿新
  • 记一次业余项目的敏捷开发实践

    本次是在原有ApiTemplate项目之上,增加一个用户登录权限控制模块,用于验证ApiTemplate项目在面对一些简单问题时,如何抽象并支持未来...

    sam dragon
  • Elasticsearch(2)PHP驱动

    安装完成composer之后。我们需要安装php的类库来对Elasticsearch进行连接。

    魔王卷子
  • Netty 高性能内存管理设计 (1)

    Netty 作为一款高性能的网络框架,需要处理海量的字节数据,而且 Netty 默认提供了池化对象的内存分配,使用完后归还到内存池,所以一套高性能的内存管理机制...

    MickyInvQ
  • 招聘测试人员

    张树臣
  • 机器学习第10天:垃圾短信识别

    这篇文章中,我们将通过贝叶斯模型来识别垃圾短信,这里也将引入分词、tfidf等概念,相对于之前的文章上了一个台阶。

    明天依旧可好

扫码关注云+社区

领取腾讯云代金券