zoukankan      html  css  js  c++  java
  • 构建基于角色、由应用程序管理的授权框架

    users --- userRoles -- roles ---roles -- rolePermission --- permission - permissionCategory
    1、权限明细表:列出所有权限名称。
    2、角色表:列出所有角色名称
    3、角色权限表:列出每个角色的权限。
    4、用户表:
    5、用户角色表:表示一个用户包含哪个几角色。
    6、页面权限表:每个页面属于哪个权限

           安全性是一个非常大的课题,本篇文章旨在探讨授权部分。
    如果你不理解安全性相关概念,可以参考如下几篇文章:
            1、Web 应用程序安全框架:http://erpcrm.cnblogs.com/articles/234776.html
            2、设计由应用程序管理的授权:http://erpcrm.cnblogs.com/articles/234793.html
            3 、.net 基于角色的安全性介绍 http://msdn.microsoft.com/library/chs/?url=/library/CHS/cpguide/html/cpconIntroductionToRole-BasedSecurity.asp

    本文假设你对.net 安全性相关概念如Principal 和Identity有所了解。
    一、分析
    先看一个基于角色授权的需求:
    在一个CRM系统中,用户 “zhangsan”属于销售部的一名普通员工,“lisi”是该销售部的部门经理,“zhangsan”作为一名销售员有创建新客户的权利(customer.add),删除客户的权利(customer.delete)只有部门经理才有。
    这种需求,我们一般情况下,建立两个角色(employees,managers),zhangsan属于employees,  lisi属于managers,
    然后我们再定义employees有customer.add的权利,managers两个权利都有,这样就基本满足了这种需求。

    现在有一个更深层次的需求:zhangsan作为销售员需要报销一些行销费用,在报销流程中,1000元以下的费用由部门经理审批,超过1000元的由总经理审批,类似这样的需求,我们认为属于业务逻辑范畴,本授权框架不解决类似问题。

    本框架的数据持久部分如下图:
    本持久部分是该授权框架的一个持久实现,本框架数据持久部分采用porvider模型,允许你定义自己的持久实现。


    二 利用.net实现该框架
    在.net中基于角色安全性的两个重要概念就是 Principal(主体),Identity(标示)。
    在该框架中 ECubePrincipal 实现了IPrincipal接口,ECubeIdentity 实现了IIdentity接口。
     

    using System;
    using System.Runtime.Serialization;
    using System.Configuration;

    namespace ECube.Business.Security
    {
        [SerializableAttribute]
        
    public class ECubeIdentity : System.Security.Principal.IIdentity
        
    {
            
    private string _Name;
            
    private string _AuthenticationType;
            
    private bool _IsAuthenticated;
        

            
    public ECubeIdentity()
            
    {
                _AuthenticationType 
    = "ECubeCustom";        
            }

            
    internal ECubeIdentity(String name, Boolean isAuthenticated)
            
    {
                _Name 
    = name;
                _IsAuthenticated 
    = isAuthenticated;
            }


               
    public string Name
            
    {
                
    get
                
    {
                    
    return _Name;
                }

            }

            
    public bool IsAuthenticated
            
    {
                
    get
                
    {
                    
    return _IsAuthenticated;
                }

            }

            
    public string AuthenticationType
            
    {
                
    get
                
    {
                    
    return _AuthenticationType;
                }

            }

        }

    }

    上面这个是ECubeIdentity的源码,比较简单,没啥可说的。
    下面看看ECubePrinicpal:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Security;
    using System.Security.Principal;
    using System.Web.Security;
    using ECube.Business.SystemFramework;
    using ECube.Business.Security.Data;

    namespace ECube.Business.Security
    {
        [SerializableAttribute]
        
    public class ECubePrincipal : IPrincipal
        
    {
            IIdentity _Identity;
            
    private static  IUserProvider _UserProvider;
            
    private static  IRoleProvider _RoleProvider;
            
    private static  IPermissionProvider _PermissionProvider;
            
    private static  String[] _Roles;

            
    private Dictionary<String, Boolean> permissions = null;

            
    public  ECubePrincipal(IIdentity identity)
            
    {
                _Identity 
    = identity;

                
    //如果在ASP.NET 中是Forms授权
                if(identity is System.Web.Security.FormsIdentity)
                
    {

                    
    //检查Membership.Provider是否实现 IUserProvider;
                    if (!(System.Web.Security.Membership.Provider is IUserProvider))
                    
    {
                        
    throw new SecurityException("System.Web.Security.Membership.Provider Must is IUserProvider Type.");
                    }

                    
    //检查Roles.Provider是否实现 IRoleProvider;
                    if (!(System.Web.Security.Roles.Provider is IRoleProvider))
                    
    {
                        
    throw new SecurityException("System.Web.Security.Roles.Provider Must is IRoleProvide Type.");
                    }


                    _UserProvider 
    = Membership.Provider as IUserProvider;
                    _RoleProvider 
    = Roles.Provider as IRoleProvider;
                }

                
    else if(identity is System.Security.Principal.WindowsIdentity)
                
    {

                }

                
    else if(identity is System.Web.Security.PassportIdentity)
                
    {

                }

                
    else if(identity is System.Security.Principal.GenericIdentity)
                
    {

                }

                
    else if(identity is ECubeIdentity)
                
    {
                    
                }

                
    else
                
    {

                }


                
    //取得该用户的 “许可集”
                permissions = PermissionProvider.GetPermissions(identity.Name);
                    
            }


            
    /// <summary>
            
    /// 返回角色数据提供者。
            
    /// </summary>

            public static  IRoleProvider RoleProvider
            
    {
                
    get
                
    {
                    
    if (_RoleProvider == null)
                    
    {
                        
    //首先检查当前应用程序的配置中是否指定了 角色提供者
                        String roleProviderName = BizApplication.Current.Parameters["RoleProviderName"].Value;
                        
    //如果没有
                        if (String.IsNullOrEmpty(roleProviderName))
                        
    {
                            
    //取得配置文件中Role段的默认角色提供者名字
                            roleProviderName = BizSecuritySection.Role.DefaultProvider;
                        }


                        
    if (!String.IsNullOrEmpty(roleProviderName))
                        
    {
                            
    //根据名字,取得对应的Provider 
                            _RoleProvider = BizSecuritySection.Role.GetProvider(roleProviderName);
                        }


                        
    //如果还没有取到,并且定义了提供者
                        if (_RoleProvider == null && BizSecuritySection.Role.Providers.Count > 0)
                        
    {
                            
    //取得第一个
                            _RoleProvider = BizSecuritySection.Role.GetProvider(BizSecuritySection.Role.Providers[0]);
                        }


                        
    //如果还没取得
                        if (_RoleProvider == null)
                        
    {
                             
    //使用默认的。
                            _RoleProvider = new Role(); 
                        }


                    }

                    
    return _RoleProvider;
                }

            }

            
    /// <summary>
            
    /// 返回用户提供者。
            
    /// </summary>

            public static  IUserProvider UserProvider
            
    {
                
    get
                
    {
                    
    if (_UserProvider == null)
                    
    {
                        
    //首先检查当前应用程序的配置中是否指定了 
                        String userProviderName = BizApplication.Current.Parameters["UserProviderName"].Value;

                        
    //如果没有
                        if (String.IsNullOrEmpty(userProviderName))
                        
    {
                            
    //取得配置文件中User段的默认提供者名字
                            userProviderName = BizSecuritySection.User.DefaultProvider;
                        }


                        
    if (!String.IsNullOrEmpty(userProviderName))
                        
    {
                            
    //根据名字,取得对应的Provider 
                            _UserProvider = BizSecuritySection.User.GetProvider(userProviderName);
                        }

                        
    //如果还没有取到,并且定义了提供者
                        if (_UserProvider == null && BizSecuritySection.User.Providers.Count > 0)
                        
    {
                            
    //取得第一个
                            _UserProvider = BizSecuritySection.User.GetProvider(BizSecuritySection.User.Providers[0]);
                        }


                        
    //如果还没取得
                        if (_UserProvider == null)
                        
    {
                            
    //使用默认的。
                            _UserProvider = new User();
                        }

                    }

                    
                    
    return _UserProvider;
                }

            }

            
    /// <summary>
            
    /// 返回许可提供者.
            
    /// </summary>

            public static  IPermissionProvider PermissionProvider
            
    {
                
    get
                
    {

                    
    if (_PermissionProvider == null)
                    
    {
                        
    //首先检查当前应用程序的配置中是否指定了
                        String permissionProviderName = BizApplication.Current.Parameters["PermissionProviderName"].Value;
                        
    //如果没有
                        if (String.IsNullOrEmpty(permissionProviderName))
                        
    {
                            
    //取得配置文件中User段的默认提供者名字
                            permissionProviderName = BizSecuritySection.Permission.DefaultProvider;
                        }

                        
    if (!String.IsNullOrEmpty(permissionProviderName))
                        
    {
                            
    //根据名字,取得对应的Provider
                            _PermissionProvider = BizSecuritySection.Permission.GetProvider(permissionProviderName);
                        }

                        
    //如果还没有取到,并且定义了提供者
                        if (_PermissionProvider == null && BizSecuritySection.Permission.Providers.Count > 0)
                        
    {
                            
    //取得第一个
                            _PermissionProvider = BizSecuritySection.Permission.GetProvider(BizSecuritySection.Permission.Providers[0]);
                        }

                        
    //如果还没取得
                        if (_PermissionProvider == null)
                        
    {
                            
    //使用默认的。
                            _PermissionProvider = new Permission();
                        }

                    }

                    
    return _PermissionProvider;
                }

            }

           
            
    /// <summary>
            
    /// 注销
            
    /// </summary>

            public void Logout()
            
    {
                
    this._Identity = null;
                System.Threading.Thread.CurrentPrincipal 
    = null;
            }


            
    /// <summary>
            
    /// 登录,这是一个静态方法
            
    /// </summary>
            
    /// <param name="usrName">用于验证的用户名。</param>
            
    /// <param name="usrPwd">用于验证的密码</param>
            
    /// <param name="isSecurity">是否使用安全的提示,如果否:当验证错误时,提示非常明确,如“没有找到该用户!”,“密码错误!”。
            
    /// 否则,给出非常模糊的提示。
            
    /// </param>

            public static  void  Login(string usrName, string usrPwd, bool isSecurity)
            
    {
              
                
    try
                
    {
                    
    if (_UserProvider != null)
                    
    {
                        
    if (_UserProvider.ValidateUser(usrName, usrPwd, isSecurity))
                        
    {
                          

                            DSSecurity.SECRolesDataTable roleTable 
    = RoleProvider.GetRolesForUser(usrName);

                            _Roles 
    = new String[roleTable.Count];
                            
    for (int i = 0; i < roleTable.Count; i++)
                            
    {
                                _Roles[i] 
    = roleTable[i].Name;
                            }


                           
                            IIdentity identity 
    = new ECubeIdentity(usrName, true);                            
                            System.Threading.Thread.CurrentPrincipal 
    = new ECubePrincipal(identity );
                            
    return;
                        }


                    }

                }

                
    catch (System.Exception ex)
                
    {
                    
    if (ex is SecurityException)
                    
    {
                        
    throw;
                    }

                    
    else
                    
    {
                        
    //做一些记录等工作。
                    }

                }

               

            }

            
       
            
    /// <summary>
            
    /// 检查权限。
            
    /// </summary>
            
    /// <param name="permissionKey">权限的键:如在增加客户的权限可以描述为:“Customer.add”</param>
            
    /// <returns></returns>

            public Boolean CheckPermission(String permissionKey)
            
    {
                
    if (String.IsNullOrEmpty(permissionKey))
                
    {
                    
    return false;
                }


                
    if (_Identity == null)
                
    {
                    
    return false;
                }


                
    if (!_Identity.IsAuthenticated || permissions == null || permissions.Count == 0)
                
    {
                    
    return false;
                }


                
    return permissions[permissionKey];

            }


         
            
    #region IPrincipal 成员

           
    public  IIdentity Identity
            
    {
                
    get
                
    {
                    
    if (_Identity == null)
                    
    {
                        _Identity 
    = new ECubeIdentity("guest",false);
                    }

                    
    return _Identity;

                }

            }


            
    public bool IsInRole(string role)
            
    {
                
    throw new Exception("The method or operation is not implemented.");
            }


            
    #endregion

        }

    }

    如果你只是想使用本框架的话,你接触到的只会是ECubePrincipal类。如果你想实现自己的持久,你可以实现
    IRoleProvider、IUserProvider、IPerssionsProvider接口,当然了还需要一些配置(不过我会实现一个工具来完成这个过程)
    如何使用本框架进行登录验证呢?
    场景一:
    考虑一个非ASP.NET 环境,你在登录窗口的登录按钮的CLICK 事件中,可以这样写:
    {
            if( ECubePrincipal.Login(usernmae,userpwd,true))
            {
                ....
            }
    }
    就这么简单。
    场景二:
    ASp.net环境,asp.net 中可能稍微复杂一些,因为asp.net 有自己的验证机制,但也不是没办法。
    我们可以在Global.asax的方

    法中写如下代码(当然你可以自己实现一个IhttpModule,不一定非得在Global.asax中)

    void Applicaiton_AuthenticateRequest(object sender, EventArgs e)
        
    {
            
    if (sender == null)
            
    {
                
    return;
            }


            HttpContext Context 
    = ((HttpApplication)sender).Context;
            
    if (Context.User != null && !(Context.User is ECube.Business.Security.ECubePrincipal))
            
    {
                
    if (Context.User.Identity is FormsIdentity)
                
    {
                    
    if (Membership.Provider is ECube.Business.Security.IUserProvider &&
                        Roles.Provider 
    is ECube.Business.Security.IRoleProvider)
                    
    {
                        Context.User 
    = new ECube.Business.Security.ECubePrincipal(Context.User.Identity);
                    }

                }

                
    else
                
    {
                    Context.User 
    = new ECube.Business.Security.ECubePrincipal(Context.User.Identity);
                }

            }

            
        }


     

    从上面这两个场景可以看到:使用ECubePrincipal进行登录验证有2种方法
     一是利用Login。,二是直接new ECubePrincipal 。


    三、如何进行授权

    验证授权验证非常简单:
    class Customer
    {
       void Add()
       {
        ECubePrincipal princ = System.Threading.Thread.CurrentPrincipal as ECube.Business.Security.ECubePrincipal
       if(princ != null && princ.CheckPermission("customer.add"))
    {


       }
    }
    如果你在ASP.NET页面中,你还可以这样写:
    ECubePrincipal princ = Page.User as ECube.Business.Security.ECubePrincipal
       if(princ != null && princ.CheckPermission("customer.add"))
    {
    .
    }


    四、结束语
    本框架构建在.net 2.0平台上,适用于asp.net和非asp.net环境中。
    在该文章中,没有介绍的类,如IUserProivder, BizApplication(读写配置文件的类),以及实现持久化的类 ,你可以参考我的源码(其实该提供一个类图,但我的VISIO反相不了,有谁知道VISIO反相vss2005的插件,麻烦告诉我一声)。
    地址为:https://files.cnblogs.com/erpcrm/ECubeSecurity.rar
    该源码可能无法编译通过(因为我刚改动了数据库结构),本文属于<<利用asp.net 2.0构建企业级门户平台>> 系列文章的一部分,将来的代码你可以参考这个系列文章中的源码。

  • 相关阅读:
    tcp流协议产生的粘包问题和解决方案
    使用fork并发处理多个client的请求和对等通信p2p
    最简单的回射客户/服务器程序、time_wait 状态
    C/S程序的一般流程和基本socket函数
    socket概述和字节序、地址转换函数
    IP数据报格式和IP地址路由
    利用ARP和ICMP协议解释ping命令
    TCP/IP协议栈与数据报封装
    从汇编角度来理解linux下多层函数调用堆栈运行状态
    read/write函数与(非)阻塞I/O的概念
  • 原文地址:https://www.cnblogs.com/jackzhang/p/584748.html
Copyright © 2011-2022 走看看