ArcGIS Server 可通过自定义标识存储中的用户和角色获得安全保护。为此,ArcGIS Server 支持 ASP.NET 成员资格和角色提供程序。
要使用 ASP.NET 配置自定义标识存储,请执行以下步骤:
配置自定义 ASP.NET 提供程序后,可以在管理器中查看其内容,并使用自定义存储中的角色来设置 Web 服务上的权限。
为 ArcGIS Server 实施一个自定义的 ASP.NET 提供程序
要通过自定义标识存储中的用户来确保 ArcGIS Server 的安全性,必须开发一个实施以下方法的 .NET framework 4.5.1 ASP.NET 成员提供程序:
- FindUsersByName
- GetAllUsers
- GetUser
- ValidateUser
要通过自定义标识存储中的角色来确保 ArcGIS Server 的安全性,必须开发一个实施以下方法的 .NET framework 4.5.1 ASP.NET 角色提供程序:
- GetAllRoles
- GetRolesForUser
- GetUsersInRole
注:
实施自定义 ASP.NET 提供程序时,建议的方法是将其在 ArcGIS Server 中以只读的标识存储形式进行显示。如果您希望通过 ArcGIS Server 创建和修改用户/角色信息,则需要在自定义的 ASP.NET 提供程序中实施其他方法,正如以下实现示例所示。
在 ArcGIS Server 上部署自定义提供程序
- 在 .dll 文件中构建自定义提供程序,并将其复制到托管 ArcGIS Server 的计算机中。
- 在 GAC 中安装自定义提供程序 .dll。
示例:gacutil /i MyCustomProvider.dll
配置 ArcGIS Server 以使用自定义提供程序
要将 ArcGIS Server 配置为使用自定义 ASP.NET 提供程序,必须指定 ASP.NET 提供程序的类型属性。作为可选项,还可指定提供程序所需的任意运行时属性,例如用户凭据等。
- 打开“ArcGIS Server 管理员目录”并登录。
- 单击安全性 > 配置 > 更新标识存储。
- 以 JSON 格式输入用户存储配置。该语法为:
{ "type": "ASP_NET", "class": "{Membership provider's type attribute value}", "properties": { "Property One": "value", .... "Property X": "value" } }
- 以 JSON 格式输入角色存储配置。该语法为:
{ "type": "ASP_NET", "class": "{Role provider's type attribute value}", "properties": { "Property One": "value", .... "Property X": "value" } }
- 单击更新保存配置。
实现示例
以下是使用 C# 语言的 ArcGIS Server 的 ASP.NET 成员和角色提供程序的实现示例。示例使用的是可修改的 ASP.NET 提供程序。建议的方法是将提供程序在 ArcGIS Server 中以只读的标识存储形式进行显示。
示例成员提供程序
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.Hosting;
using System.Web.Management;
using System.Web;
using System.Security.Permissions;
using System.Xml;
using System.IO;
namespace CustomProvider
{
public class XmlMembershipProvider : MembershipProvider
{
private string _appName = null;
private string _providerName = null;
private string _userStore;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
if (config == null)
throw new ArgumentNullException("config");
if (String.IsNullOrEmpty(name))
name = "CustomProvider.XmlMembershipProvider";
base.Initialize(name, config);
_providerName = name;
string path = config["FileName"];
if (String.IsNullOrEmpty(path))
path = "C:\\temp\\IdentityStore.xml";
else
_userStore = path;
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write,_userStore);
permission.Demand();
}
public override string ApplicationName
{
get
{
return _appName;
}
set
{
_appName = 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)
{
return true;
}
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
MembershipUser newUser = new MembershipUser(
_providerName,
username,
null,
email,
"Secret Question",
username,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
XmlDocument _usersList = ReadUsersFromStore();
XmlNode newUserNode = _usersList.CreateNode(XmlNodeType.Element, "User", null);
XmlNode newUserInfoNode = _usersList.CreateElement("UserName");
newUserInfoNode.InnerText = username;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Password");
newUserInfoNode.InnerText = password;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("FullName");
newUserInfoNode.InnerText = username;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Email");
newUserInfoNode.InnerText = email;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Roles");
newUserNode.AppendChild(newUserInfoNode);
_usersList.DocumentElement.AppendChild(newUserNode);
_usersList.Save(_userStore);
status = MembershipCreateStatus.Success;
return newUser;
}
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
XmlDocument _usersList = ReadUsersFromStore();
XmlNode nodeToDelete = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (nodeToDelete != null)
{
_usersList.FirstChild.RemoveChild(nodeToDelete);
_usersList.Save(_userStore);
return true;
}
else
return false;
}
public override bool EnablePasswordReset
{
get { return true; }
}
public override bool EnablePasswordRetrieval
{
get { return true; }
}
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)
{
MembershipUserCollection usersColl = new MembershipUserCollection();
XmlNodeList matchingNodes = null;
XmlDocument _usersList = ReadUsersFromStore();
matchingNodes = _usersList.SelectNodes(string.Format("//*[contains(UserName,\"{0}\")]", usernameToMatch));
totalRecords = 0;
if (matchingNodes != null && matchingNodes.Count != 0)
{
totalRecords = matchingNodes.Count;
foreach (XmlNode node in matchingNodes)
{
MembershipUser newUser = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
usersColl.Add(newUser);
}
}
return usersColl;
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection usersColl = new MembershipUserCollection();
XmlDocument _usersList = ReadUsersFromStore();
XmlNodeList userNodes = _usersList.GetElementsByTagName("User");
foreach (XmlNode node in userNodes)
{
MembershipUser newUser = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"Secret Question",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
usersColl.Add(newUser);
}
totalRecords = userNodes.Count;
return usersColl;
}
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)
{
XmlDocument _usersList = ReadUsersFromStore();
MembershipUser user = null;
XmlNode node = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (node != null)
{
user = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"Secret Question",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
}
return user;
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
throw new NotImplementedException();
}
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)
{
XmlDocument _usersList = ReadUsersFromStore();
String username = user.UserName;
XmlNode nodeToUpdate = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (nodeToUpdate != null)
{
nodeToUpdate["Email"].InnerText = user.Email;
_usersList.Save(_userStore);
}
}
public override bool ValidateUser(string username, string password)
{
XmlDocument _usersList = ReadUsersFromStore();
XmlNode node = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (node != null && username.Equals(node["UserName"].InnerText) && password.Equals(node["Password"].InnerText))
return true;
else
return false;
}
private XmlDocument ReadUsersFromStore()
{
XmlDocument _usersList = new XmlDocument();
_usersList.Load(_userStore);
return _usersList;
}
} /* XmlFileMembershipProvider */
}
示例角色提供程序
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.Hosting;
using System.Web.Management;
using System.Web;
using System.Security.Permissions;
using System.Xml;
using System.IO;
namespace CustomProvider
{
public class XmlRoleProvider : RoleProvider {
private string _appName = null;
private string _providerName = null;
private string _roleStore = null;
XmlDocument _xmlRoleList = null;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) {
if (config == null) throw new ArgumentNullException("config");
if (String.IsNullOrEmpty(name)) name = "CustomProvider.XmlRoleProvider";
base.Initialize(name, config);
_providerName = name;
string path = config["FileName"];
if (String.IsNullOrEmpty(path)) path = "C:\\temp\\IdentityStore.xml";
else _roleStore = path;
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write, _roleStore);
permission.Demand();
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames) {
XmlDocument userRoleDoc = ReadUserRolesFromStore();
foreach (string user in usernames) {
XmlNode userRoleNode = userRoleDoc.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", user));
String roleList = userRoleNode["Roles"].InnerText;
foreach (string role in roleNames) {
if(roleList.Equals("")) roleList += role;
else roleList += "," + role;
}
userRoleNode.RemoveChild(userRoleNode.LastChild);
XmlNode newRoleListNode = userRoleDoc.CreateElement("Roles");
newRoleListNode.InnerText = roleList;
userRoleNode.AppendChild(newRoleListNode);
}
userRoleDoc.Save(_roleStore);
}
public override string ApplicationName {
get {
return _appName;
}
set {
_appName = value;
}
}
public override void CreateRole(string roleName) {
ReadRolesFromStore();
XmlNode newRoleNode = _xmlRoleList.CreateNode(XmlNodeType.Element, "Role", null);
XmlNode newUserInfoNode = _xmlRoleList.CreateElement("RoleName");
newUserInfoNode.InnerText = roleName;
newRoleNode.AppendChild(newUserInfoNode);
_xmlRoleList.DocumentElement.AppendChild(newRoleNode);
_xmlRoleList.Save(_roleStore);
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { ReadRolesFromStore();
XmlNode nodeToDelete = _xmlRoleList.SelectSingleNode(string.Format("//*[RoleName=\"{0}\"]", roleName));
if (nodeToDelete != null) {
_xmlRoleList.FirstChild.RemoveChild(nodeToDelete);
_xmlRoleList.Save(_roleStore);
return true;
}
else return false;
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch) {
throw new NotImplementedException();
}
public override string[] GetAllRoles() {
ArrayList roleArrayList = ReadRolesFromStore();
return (string[])roleArrayList.ToArray(typeof(string));
}
public override string[] GetRolesForUser(string username) {
XmlDocument xmlUserRolesList = ReadUserRolesFromStore();
XmlNode userRoleNode = xmlUserRolesList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
String[] roleList = userRoleNode["Roles"].InnerText.Split(',');
if (roleList[0] == "") return new string[0];
else return roleList;
}
public override string[] GetUsersInRole(string roleName) {
ArrayList userList = new ArrayList();
XmlDocument xmlUserRolesList = ReadUserRolesFromStore();
XmlNodeList userRoleNodes = xmlUserRolesList.GetElementsByTagName("User");
if (userRoleNodes != null) {
int numRoles = userRoleNodes.Count;
foreach(XmlNode node in userRoleNodes) {
String[] roleList = node["Roles"].InnerText.Split(',');
foreach (string item in roleList) {
if (item.Equals(roleName)) {
String username = node["UserName"].InnerText;
userList.Add(username);
break;
}
}
}
}
return (string[])userList.ToArray(typeof(string));
}
public override bool IsUserInRole(string username, string roleName) {
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) {
XmlDocument userRoleDoc = ReadUserRolesFromStore();
foreach (string user in usernames) {
XmlNode userRoleNode = userRoleDoc.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", user));
ArrayList roleList = new ArrayList();
roleList.AddRange(userRoleNode["Roles"].InnerText.Split(','));
foreach (string role in roleNames) {
if (roleList.Contains(role)) roleList.Remove(role);
}
userRoleNode.RemoveChild(userRoleNode.LastChild);
XmlNode newRoleListNode = userRoleDoc.CreateElement("Roles");
if( roleList.Count > 0 ) newRoleListNode.InnerText = string.Join(",", (string[])roleList.ToArray(Type.GetType("System.String")));
userRoleNode.AppendChild(newRoleListNode);
}
userRoleDoc.Save(_roleStore);
}
public override bool RoleExists(string roleName) {
throw new NotImplementedException();
}
private ArrayList ReadRolesFromStore() {
_xmlRoleList = new XmlDocument();
_xmlRoleList.Load(_roleStore);
XmlNodeList roleNodes = _xmlRoleList.GetElementsByTagName("Role");
ArrayList roleArrayList = null;
if (roleNodes != null) {
roleArrayList = new ArrayList();
foreach (XmlNode node in roleNodes) {
roleArrayList.Add( node["RoleName"].InnerText);
}
}
return roleArrayList;
}
private XmlDocument ReadUserRolesFromStore() {
XmlDocument xmlUserRolesList = new XmlDocument();
xmlUserRolesList.Load(_roleStore);
return xmlUserRolesList;
}
}
}
示例标识存储配置 JSON
用户存储 JSON
{
"type": "ASP_NET", "class": "CustomProvider.XmlMembershipProvider,CustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=b02390eb7f2c02c4", "properties": {
"FileName": "C:\\arcgisserver\\identitystore\\IdentityStore.xml"
}
}
角色存储 JSON
{
"type": "ASP_NET", "class": "CustomProvider.XmlRoleProvider,CustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=b02390eb7f2c02c4", "properties": {
"FileName": "C:\\arcgisserver\\identitystore\\IdentityStore.xml"
}
}
示例标识存储
<IdentityStore>
<User>
<UserName>amy</UserName>
<Password>amy</Password>
<FullName>amy</FullName>
<Email>amy@amy.amy</Email>
<Roles>admins</Roles>
</User>
<Role>
<RoleName>admins</RoleName>
</Role>
</IdentityStore>