.NET中的身份验证,授权,用户和角色管理以及一般安全性

Saa*_*ail 31 c# security authorization roles

我需要知道如何为C#应用程序实现一般安全性.在这方面我有什么选择?如果满足我的需求,我宁愿使用现有的框架 - 我不想重新发明轮子.

我的要求如下:

  • 通常的用户名/密码验证
  • 管理用户 - 为用户分配权限
  • 管理角色 - 将用户分配给角色,为角色分配权限
  • 用户根据用户名和角色授权

我正在寻找一个由.Net社区进行时间处理和使用的免费/开源框架/库.

我的应用程序采用客户端/服务器方法,服务器作为Windows服务运行,连接到SQL Server数据库.客户端和服务器之间的通信将通过WCF进行.

这是很重要的一件事是,我需要能够给特定用户或角色的权限分配给查看/更新/删除特定的实体,无论是客户或产品等.例如,杰克可以查看某些10的3客户,但只更新微软,雅虎和谷歌客户的详细信息,并且只能删除雅虎.

Mar*_*ell 33

对于粗粒度安全性,您可能会发现内置的主体代码很有用; 用户对象(及其角色)由"主体"在.NET中控制,但有用的是运行时本身可以强制执行此操作.

委托人的实现可以是实现定义的,你通常可以注入自己的; 例如在WCF中.

要查看运行时强制执行粗略访问(即可以访问哪些功能,但不限于哪些特定数据):

static class Roles {
    public const string Administrator = "ADMIN";
}
static class Program {
    static void Main() {
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Fred"), new string[] { Roles.Administrator });
        DeleteDatabase(); // fine
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Barney"), new string[] { });
        DeleteDatabase(); // boom
    }

    [PrincipalPermission(SecurityAction.Demand, Role = Roles.Administrator)]
    public static void DeleteDatabase()
    {
        Console.WriteLine(
            Thread.CurrentPrincipal.Identity.Name + " has deleted the database...");
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这对细粒度访问没有帮助(即"Fred可以访问客户A而不访问客户B").


额外; 当然,对于细粒度,您可以通过检查IsInRole主体来简单地在运行时检查所需的角色:

static void EnforceRole(string role)
{
    if (string.IsNullOrEmpty(role)) { return; } // assume anon OK
    IPrincipal principal = Thread.CurrentPrincipal;
    if (principal == null || !principal.IsInRole(role))
    {
        throw new SecurityException("Access denied to role: " + role);
    }
}
public static User GetUser(string id)
{
    User user = Repository.GetUser(id);
    EnforceRole(user.AccessRole);
    return user;
}
Run Code Online (Sandbox Code Playgroud)

您还可以编写自己的主体/身份对象来执行角色的延迟测试/缓存,而不必事先了解它们:

class CustomPrincipal : IPrincipal, IIdentity
{
    private string cn;
    public CustomPrincipal(string cn)
    {
        if (string.IsNullOrEmpty(cn)) throw new ArgumentNullException("cn");
        this.cn = cn;
    }
    // perhaps not ideal, but serves as an example
    readonly Dictionary<string, bool> roleCache =
        new Dictionary<string, bool>();
    public override string ToString() { return cn; }
    bool IIdentity.IsAuthenticated { get { return true; } }
    string IIdentity.AuthenticationType { get { return "iris scan"; } }
    string IIdentity.Name { get { return cn; } }
    IIdentity IPrincipal.Identity { get { return this; } }

    bool IPrincipal.IsInRole(string role)
    {
        if (string.IsNullOrEmpty(role)) return true; // assume anon OK
        lock (roleCache)
        {
            bool value;
            if (!roleCache.TryGetValue(role, out value)) {
                value = RoleHasAccess(cn, role);
                roleCache.Add(role, value);
            }
            return value;
        }
    }
    private static bool RoleHasAccess(string cn, string role)
    {
        //TODO: talk to your own security store
    }
}
Run Code Online (Sandbox Code Playgroud)