Authentication, Authorization, User and Role Management and general Security in .NET

前端 未结 7 1501
星月不相逢
星月不相逢 2021-01-29 23:20

I need to know how to go about implementing general security for a C# application. What options do I have in this regard? I would prefer to use an existing framework if it meets

7条回答
  •  忘掉有多难
    2021-01-29 23:41

    For coarse-grained security, you might find the inbuilt principal code useful; the user object (and their roles) are controlled in .NET by the "principal", but usefully the runtime itself can enforce this.

    The implementation of a principal can be implementation-defined, and you can usually inject your own; for example in WCF.

    To see the runtime enforcing coarse access (i.e. which functionality can be accessed, but not limited to which specific data):

    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...");
        }
    }
    

    However, this doesn't help with the fine-grained access (i.e. "Fred can access customer A but not customer B").


    Additional; Of course, for fine-grained, you can simply check the required roles at runtime, by checking IsInRole on the principal:

    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;
    }
    

    You can also write your own principal / identity objects that do lazy tests / caching of the roles, rather than having to know them all up-front:

    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 roleCache =
            new Dictionary();
        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
        }
    }
    

提交回复
热议问题