服务器用户配置文件在哪里找,SharePoint Server 中的服务器到服务器身份验证和用户配置文件...

SharePoint Server 中的服务器到服务器身份验证和用户配置文件

8/24/2017

本文内容

适用于:

5eab73b3561b8952d33fdf07f3248b23.png 2013

5eab73b3561b8952d33fdf07f3248b23.png 2016

5eab73b3561b8952d33fdf07f3248b23.png 2019

fd6898760fed4723ca66a34a2689607f.png Microsoft 365

使用服务器间身份验证,支持服务器间身份验证的服务器可以代表用户从另一台服务器访问和请求获取资源。因此,运行 SharePoint Server 并处理传入资源请求的服务器必须能够完成以下两项任务:

将请求解析到特定的 SharePoint 用户

确定与用户关联的角色声明组,这是一个称作解除冻结 用户标识的过程

为了解除冻结用户标识,可执行服务器间身份验证的服务器将请求访问 SharePoint 资源。SharePoint Server 将提取传入安全令牌中的声明,并将它解析为特定的 SharePoint 用户。默认情况下,SharePoint Server 使用内置 User Profile Service 应用程序来解析标识。

用于查找相应用户配置文件的关键用户属性如下:

Windows 安全标识符 (SID)

Active Directory 域服务 (AD DS) 用户主体名称 (UPN)

简单邮件传输协议 (SMTP) 地址

会话初始协议 (SIP) 地址

因此,这些用户属性中至少有一个必须是用户配置文件中的最新属性。

备注

仅对于 SharePoint Server 2013,建议定期执行从标识存储到 User Profile Service 应用程序的同步。有关详细信息,请参阅为 SharePoint Server 2013 规划配置文件同步。

此外,SharePoint Server 在基于这四个属性的给定查找查询的 User Profile Service 应用程序中仅需一个匹配条目。否则,它会返回已找到多个用户配置文件的错误情况。因此,应定期删除 User Profile Service 应用程序中过时的用户配置文件,以免存在多个共用这四个属性的用户配置文件。

如果用户配置文件和用户的相关组成员身份并未同步,SharePoint Server 可能会错误地拒绝访问给定资源。因此,请确保相应组成员身份已与 User Profile Service 应用程序同步。对于 Windows 声明,User Profile Service 应用程序将导入前面提及的四个关键用户属性和组成员身份。

对于基于表单和基于安全声明标记语言 (SAML) 的声明身份验证,您必须执行以下操作之一:

创建与 User Profile Service 应用程序支持的数据源的同步连接,并将该连接与基于表单或 SAML 的特定身份验证提供程序相关联。此外,还必须将用户存储中的属性映射到前面提及的四个用户属性,或者可从数据源中获得的一样多的属性。

创建并部署自定义组件以手动执行同步。这对于不使用 Windows 的用户而言是最可能的选项。请注意,当解除冻结用户的标识以获取其角色声明时,将调用基于表单或 SAML 的身份验证提供程序。

针对请求服务器的用户解除冻结

如果请求服务器运行 Exchange Server 2016 或 Skype for Business Server 2015(使用标准 Windows 身份验证方法),请求服务器发送的传入安全令牌将包含用户 UPN,且可能会包含其他属性,如 SMTP、SIP 以及用户标识的 SID。接收服务器 SharePoint Server 使用此信息查找用户配置文件。

对于运行 SharePoint Server 的请求服务器,接收服务器通过以下基于声明的身份验证方法解除冻结用户:

对于 Windows 声明身份验证,SharePoint Server 使用 AD DS 属性查找用户的用户配置文件(例如,UPN 或 SID 值)及其角色声明(组成员身份)。

对于基于表单的身份验证,SharePoint Server 使用 Account 属性查找用户的配置文件,再调用角色提供程序和其他所有自定义声明提供程序,以获取相应的角色声明组。例如, SharePoint Server 使用 AD DS 中、SQL Server 等数据库中或轻型目录访问协议 (LDAP) 数据存储中的属性,查找代表用户的用户配置文件(例如,UPN 或 SID 值)。若要同步基于表单的提供程序,组件至少应当使用用户的帐户名称填充用户配置文件。还可以创建自定义声明提供程序,将其他声明作为属性导入用户配置文件中。

对于基于 SAML 的声明身份验证,SharePoint Server 使用 AccountName 属性查找用户的配置文件,再调用 SAML 提供程序和其他所有自定义声明提供程序,以获取相应的角色声明组。用户标识声明应当通过相应 SAML 声明提供程序(应配置为填充用户配置文件)映射到用户配置文件中的 Account 属性。同样,UPN 声明应当映射到 UPN 属性,且 SMTP 声明应当映射到 SMTP 属性。若要复制用户通常会从标识提供程序获取的声明组,必须通过声明扩充添加这些声明,包括角色声明。自定义声明提供程序必须将这些声明作为属性导入用户配置文件中。

另请参阅

概念

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用VS编写的FTP服务器软件,C#网络程序编程学习用。 代码: using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Windows.Forms; namespace FtpServer { public partial class FtpServerForm : Form { TcpListener myTcpListener = null; private Thread listenThread; // 保存用户名和密码 Dictionary users; public FtpServerForm() { InitializeComponent(); // 初始化用户名和密码 users = new Dictionary(); users.Add("admin", "admin"); // 设置默认的主目录 tbxFtpRoot.Text = "F:/MyFtpServerRoot/"; IPAddress[] ips = Dns.GetHostAddresses(""); tbxFtpServerIp.Text = ips[5].ToString(); tbxFtpServerPort.Text = "21"; lstboxStatus.Enabled = false; } // 启动服务器 private void btnFtpServerStartStop_Click(object sender, EventArgs e) { if (myTcpListener == null) { listenThread = new Thread(ListenClientConnect); listenThread.IsBackground = true; listenThread.Start(); lstboxStatus.Enabled = true; lstboxStatus.Items.Clear(); lstboxStatus.Items.Add("已经启动Ftp服务..."); btnFtpServerStartStop.Text = "停止"; } else { myTcpListener.Stop(); myTcpListener = null; listenThread.Abort(); lstboxStatus.Items.Add("Ftp服务已停止!"); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; btnFtpServerStartStop.Text = "启动"; } } // 监听端口,处理客户端连接 private void ListenClientConnect() { myTcpListener = new TcpListener(IPAddress.Parse(tbxFtpServerIp.Text), int.Parse(tbxFtpServerPort.Text)); // 开始监听传入的请求 myTcpListener.Start(); AddInfo("启动FTP服务成功!"); AddInfo("Ftp服务器运行...[点击”停止“按钮停止FTP服务]"); while (true) { try { // 接收连接请求 TcpClient tcpClient = myTcpListener.AcceptTcpClient(); AddInfo(string.Format("客户端({0})与本机({1})建立Ftp连接", tcpClient.Client.RemoteEndPoint, myTcpListener.LocalEndpoint)); User user = new User(); user.commandSession = new UserSeesion(tcpClient); user.workDir = tbxFtpRoot.Text; Thread t = new Thread(UserProcessing); t.IsBackground = true; t.Start(user); } catch { break; } } } // 处理客户端用户请求 private void UserProcessing(object obj) { User user = (User)obj; string sendString = "220 FTP Server v1.0"; RepleyCommandToUser(user, sendString); while (true) { string receiveString = null; try { // 读取客户端发来的请求信息 receiveString = user.commandSession.streamReader.ReadLine(); } catch(Exception ex) { if (user.commandSession.tcpClient.Connected == false) { AddInfo(string.Format("客户端({0}断开连接!)", user.commandSession.tcpClient.Client.RemoteEndPoint)); } else { AddInfo("接收命令失败!" + ex.Message); } break; } if (receiveString == null) { AddInfo("接收字符串为null,结束线程!"); break; } AddInfo(string.Format("来自{0}:[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, receiveString)); // 分解客户端发来的控制信息的命令和参数 string command = receiveString; string param = string.Empty; int index = receiveString.IndexOf(' '); if (index != -1) { command = receiveString.Substring(0, index).ToUpper(); param = receiveString.Substring(command.Length).Trim(); } // 处理不需登录即可响应的命令(这里只处理QUIT) if (command == "QUIT") { // 关闭TCP连接并释放与其关联的所有资源 user.commandSession.Close(); return; } else { switch (user.loginOK) { // 等待用户输入用户名: case 0: CommandUser(user, command, param); break; // 等待用户输入密码 case 1: CommandPassword(user, command, param); break; // 用户名和密码验证正确后登陆 case 2: switch (command) { case "CWD": CommandCWD(user, param); break; case "PWD": CommandPWD(user); break; case "PASV": CommandPASV(user); break; case "PORT": CommandPORT(user, param); break; case "LIST": CommandLIST(user, param); break; case "NLIST": CommandLIST(user, param); break; // 处理下载文件命令 case "RETR": CommandRETR(user, param); break; // 处理上传文件命令 case "STOR": CommandSTOR(user, param); break; // 处理删除命令 case "DELE": CommandDELE(user, param); break; // 使用Type命令在ASCII和二进制模式进行变换 case "TYPE": CommandTYPE(user, param); break; default: sendString = "502 command is not implemented."; RepleyCommandToUser(user, sendString); break; } break; } } } } // 想客户端返回响应码 private void RepleyCommandToUser(User user, string str) { try { user.commandSession.streamWriter.WriteLine(str); AddInfo(string.Format("向客户端({0})发送[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, str)); } catch { AddInfo(string.Format("向客户端({0})发送信息失败", user.commandSession.tcpClient.Client.RemoteEndPoint)); } } // 向屏幕输出显示状态信息(这里使用了委托机制) private delegate void AddInfoDelegate(string str); private void AddInfo(string str) { // 如果调用AddInfo()方法的线程与创建ListView控件的线程不在一个线程时 // 此时利用委托在创建ListView的线程上调用 if (lstboxStatus.InvokeRequired == true) { AddInfoDelegate d = new AddInfoDelegate(AddInfo); this.Invoke(d, str); } else { lstboxStatus.Items.Add(str); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; lstboxStatus.ClearSelected(); } } #region 处理各个命令 #region 登录过程,即用户身份验证过程 // 处理USER命令,接收用户名但不进行验证 private void CommandUser(User user, string command, string param) { string sendString = string.Empty; if (command == "USER") { sendString = "331 USER command OK, password required."; user.userName = param; // 设置loginOk=1为了确保后面紧接的要求输入密码 // 1表示已接收到用户名,等到接收密码 user.loginOK = 1; } else { sendString = "501 USER command syntax error."; } RepleyCommandToUser(user, sendString); } // 处理PASS命令,验证用户名和密码 private void CommandPassword(User user, string command, string param) { string sendString = string.Empty; if (command == "PASS") { string password = null; if (users.TryGetValue(user.userName, out password)) { if (password == param) { sendString = "230 User logged in success"; // 2表示登录成功 user.loginOK = 2; } else { sendString = "530 Password incorrect."; } } else { sendString = "530 User name or password incorrect."; } } else { sendString = "501 PASS command Syntax error."; } RepleyCommandToUser(user, sendString); // 用户当前工作目录 user.currentDir = user.workDir; } #endregion #region 文件管理命令 // 处理CWD命令,改变工作目录 private void CommandCWD(User user, string temp) { string sendString = string.Empty; try { string dir = user.workDir.TrimEnd('/') + temp; // 是否为当前目录的子目录,且不包含父目录名称 if (Directory.Exists(dir)) { user.currentDir = dir; sendString = "250 Directory changed to '" + dir + "' successfully"; } else { sendString = "550 Directory '" + dir + "' does not exist"; } } catch { sendString = "502 Directory changed unsuccessfully"; } RepleyCommandToUser(user,sendString); } // 处理PWD命令,显示工作目录 private void CommandPWD(User user) { string sendString = string.Empty; sendString = "257 '" + user.currentDir + "' is the current directory"; RepleyCommandToUser(user, sendString); } // 处理LIST/NLIST命令,想客户端发送当前或指定目录下的所有文件名和子目录名 private void CommandLIST(User user, string parameter) { string sendString = string.Empty; DateTimeFormatInfo dateTimeFormat = new CultureInfo("en-US", true).DateTimeFormat; // 得到目录列表 string[] dir = Directory.GetDirectories(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter)) { dir = Directory.GetDirectories(user.currentDir + parameter); } else { string s = user.currentDir.TrimEnd('/'); user.currentDir = s.Substring(0, s.LastIndexOf("/") + 1); } } for (int i = 0; i < dir.Length; i++) { string folderName = Path.GetFileName(dir[i]); DirectoryInfo d = new DirectoryInfo(dir[i]); // 按下面的格式输出目录列表 sendString += @"dwr-\t" + Dns.GetHostName() + "\t" + dateTimeFormat.GetAbbreviatedMonthName(d.CreationTime.Month) + d.CreationTime.ToString(" dd yyyy") + "\t" + folderName + Environment.NewLine; } // 得到文件列表 string[] files = Directory.GetFiles(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter + "/")) { files = Directory.GetFiles(user.currentDir + parameter + "/"); } } for (int i = 0; i 1024的随机端口 // 下面这个运算算法只是为了得到一个大于1024的端口值 port = random1 << 8 | random2; try { user.dataListener = new TcpListener(localip, port); AddInfo("TCP 数据连接已打开(被动模式)--" + localip.ToString() + ":" + port); } catch { continue; } user.isPassive = true; string temp = localip.ToString().Replace('.', ','); // 必须把端口号IP地址告诉客户端,客户端接收到响应命令后, // 再通过新的端口连接服务器的端口P,然后进行文件数据传输 sendString = "227 Entering Passive Mode(" + temp + "," + random1 + "," + random2 + ")"; RepleyCommandToUser(user, sendString); user.dataListener.Start(); break; } } // 处理PORT命令,使用主动模式进行传输 private void CommandPORT(User user, string portstring) { // 主动模式时,客户端必须告知服务器接收数据的端口号,PORT 命令格式为:PORT address // address参数的格式为i1、i2、i3、i4、p1、p2,其i1、i2、i3、i4表示IP地址 // 下面通过.字符串来组合这四个参数得到IP地址 // p1、p2表示端口号,下面通过int.Parse(temp[4]) << 8) | int.Parse(temp[5] // 这个算法来获得一个大于1024的端口来发送给服务器 string sendString = string.Empty; string[] temp = portstring.Split(','); string ipString = "" + temp[0] + "." + temp[1] + "." + temp[2] + "." + temp[3]; // 客户端发出PORT命令把客户端的IP地址和随机的端口告诉服务器 int portNum = (int.Parse(temp[4]) < 0) { user.dataSession.binaryWriter.Write(bytes, 0, count); user.dataSession.binaryWriter.Flush(); count = binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamReader streamReader = new StreamReader(fs); while (streamReader.Peek() > -1) { user.dataSession.streamWriter.WriteLine(streamReader.ReadLine()); } } AddInfo("...]发送完毕!"); } finally { user.dataSession.Close(); fs.Close(); } } // 使用数据连接接收文件流(客户端发送上传文件功能) private void ReadFileByUserSession(User user, FileStream fs) { AddInfo("接收用户上传数据(文件流):[..."); try { if (user.isBinary) { byte[] bytes = new byte[1024]; BinaryWriter binaryWriter = new BinaryWriter(fs); int count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); while (count > 0) { binaryWriter.Write(bytes, 0, count); binaryWriter.Flush(); count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamWriter streamWriter = new StreamWriter(fs); while (user.dataSession.streamReader.Peek() > -1) { streamWriter.Write(user.dataSession.streamReader.ReadLine()); streamWriter.Flush(); } } AddInfo("...]接收完毕"); } finally { user.dataSession.Close(); fs.Close(); } } private void label3_Click(object sender, EventArgs e) { } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值