NopCommerce源代码分析之用户验证和权限管理

目录

    1.  介绍

    2.  UML

        2.1  实体类UML图

        2.2  业务相关UML图

    3.  核心代码分析

        3.1  实体类源代码

        3.2  业务相关源代码

     3.3  相关控制器源代码

        3.4  相关View源代码

    4.  总结


1.  介绍

     1.1  nopcommerce介绍

     nopcommerce是国外的一个高质量的开源b2c网站系统,基于EntityFramework4.0和MVC3.0,使用Razor模板引擎,有很强的插件机制,包括支付配送功能都是通过插件来实现的.    

     nopcommerce主要模块从上往下Nop.Web、Nop.Admin、Nop.Web.Framework、Nop插件、Nop.Services、Nop.Core、Nop.Data。引用的第三方模块EntityFramework,Autofac(控制反转,即依赖注入),telerik.extern.mvc(后台管理用的界面,2.0后开始使用)

      1.2  文章来由

      我之前对ASP.NET  MVC4的用户验证和权限管理这块内容理解的不深刻,一次偶然的机会使得我下载到了nopcommerce的源代码,该项目中含有访问控制功能,其功能页面如图1-1所示。

      为了进一步理解MVC4的用户验证和权限管理的内容,我用了两天时间窥视了nopcommerce的访问控制功能,略有心得体会,并以我自己的理解内容写了一个Demo:AclDemo,该项目将在下一篇分析以及提供源代码。

clipboard

                                                                                             图1-1

2.  UML

     该小节主要提供了nopcommerce项目中的访问控制功能的UML类图以及类图说明,在制作UML类图的过程中,我简化了UML类图,这样是为了让UML内容不冗余。简化后的UML类图只显示了和访问控制功能有关的内容。

     2.1  实体类UML图

clipboard[1]

    2.2  业务相关UML图

%e4%b8%bb%e8%a6%81%e4%b8%9a%e5%8a%a1%e7%b1%bb

3.  核心代码分析

     3.1  实体类源代码 

  Customer类
  
1 /// <summary>     /// Represents a customer role     /// </summary>     public partial class CustomerRole : BaseEntity     {         private ICollection<PermissionRecord> _permissionRecords;         /// <summary>         /// Gets or sets the customer role name         /// </summary>         public string Name { get; set; }         /// <summary>         /// Gets or sets a value indicating whether the customer role is active         /// </summary>         public bool Active { get; set; }         /// <summary>         /// Gets or sets a value indicating whether the customer role is system         /// </summary>         public bool IsSystemRole { get; set; }         /// <summary>         /// Gets or sets the customer role system name         /// </summary>         public string SystemName { get; set; }        /// <summary>         /// Gets or sets the permission records         /// </summary>         public virtual ICollection<PermissionRecord> PermissionRecords         {             get { return _permissionRecords ?? (_permissionRecords = new List<PermissionRecord>()); }             protected set { _permissionRecords = value; }         }     }
CustomerRole类
  
1 /// <summary>     /// Represents a permission record     /// </summary>     public partial class PermissionRecord : BaseEntity     {         private ICollection<CustomerRole> _customerRoles;         /// <summary>         /// Gets or sets the permission name         /// </summary>         public string Name { get; set; }         /// <summary>         /// Gets or sets the permission system name         /// </summary>         public string SystemName { get; set; }                  /// <summary>         /// Gets or sets the permission category         /// </summary>         public string Category { get; set; }                  /// <summary>         /// Gets or sets discount usage history         /// </summary>         public virtual ICollection<CustomerRole> CustomerRoles         {             get { return _customerRoles ?? (_customerRoles = new List<CustomerRole>()); }             protected set { _customerRoles = value; }         }        }
PermissionRecord类

 

       3.2  业务相关源代码

   
1  /// <summary>     /// Customer service interface     /// </summary>     public partial interface ICustomerService     {         #region Customers         /// <summary>         /// Get customer by username         /// </summary>         /// <param name="username">Username</param>         /// <returns>Customer</returns>         Customer GetCustomerByUsername(string username);         #endregion     }
2    
ICustomerService接口
   
1 /// <summary>     /// Customer service     /// </summary>     public partial class CustomerService : ICustomerService     {         #region Constants         #endregion         #region Fields         private readonly IRepository<Customer> _customerRepository;         private readonly IRepository<CustomerRole> _customerRoleRepository;         #endregion         #region Ctor         public CustomerService(             IRepository<Customer> customerRepository,             IRepository<CustomerRole> customerRoleRepository,)         {             this._customerRepository = customerRepository;             this._customerRoleRepository = customerRoleRepository;         }         #endregion         #region Methods         #region Customers                  /// <summary>         /// Get customer by username         /// </summary>         /// <param name="username">Username</param>         /// <returns>Customer</returns>         public virtual Customer GetCustomerByUsername(string username)         {             if (string.IsNullOrWhiteSpace(username))                 return null;             var query = from c in _customerRepository.Table                         orderby c.Id                         where c.Username == username                         select c;             var customer = query.FirstOrDefault();             return customer;         }                  #endregion                  #endregion     }
CustomerService类

 

    
1 public partial interface IAuthenticationService      {         void SignIn(Customer customer, bool createPersistentCookie);         void SignOut();         Customer GetAuthenticatedCustomer();     }
IAuthenticationService接口
    
1 public partial class FormsAuthenticationService : IAuthenticationService     {         private readonly HttpContextBase _httpContext;         private readonly ICustomerService _customerService;         private readonly CustomerSettings _customerSettings;         private readonly TimeSpan _expirationTimeSpan;         private Customer _cachedCustomer;         /// <summary>         /// Ctor         /// </summary>         /// <param name="httpContext">HTTP context</param>         /// <param name="customerService">Customer service</param>         /// <param name="customerSettings">Customer settings</param>         public FormsAuthenticationService(HttpContextBase httpContext,             ICustomerService customerService, CustomerSettings customerSettings)         {             this._httpContext = httpContext;             this._customerService = customerService;             this._customerSettings = customerSettings;             this._expirationTimeSpan = FormsAuthentication.Timeout;         }         public virtual void SignIn(Customer customer, bool createPersistentCookie)         {             var now = DateTime.UtcNow.ToLocalTime();             var ticket = new FormsAuthenticationTicket(                 1 /*version*/,                 _customerSettings.UsernamesEnabled ? customer.Username : customer.Email,                 now,                 now.Add(_expirationTimeSpan),                 createPersistentCookie,                 _customerSettings.UsernamesEnabled ? customer.Username : customer.Email,                 FormsAuthentication.FormsCookiePath);             var encryptedTicket = FormsAuthentication.Encrypt(ticket);             var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);             cookie.HttpOnly = true;             if (ticket.IsPersistent)             {                 cookie.Expires = ticket.Expiration;             }             cookie.Secure = FormsAuthentication.RequireSSL;             cookie.Path = FormsAuthentication.FormsCookiePath;             if (FormsAuthentication.CookieDomain != null)             {                 cookie.Domain = FormsAuthentication.CookieDomain;             }             _httpContext.Response.Cookies.Add(cookie);             _cachedCustomer = customer;         }         public virtual void SignOut()         {             _cachedCustomer = null;             FormsAuthentication.SignOut();         }         public virtual Customer GetAuthenticatedCustomer()         {             if (_cachedCustomer != null)                 return _cachedCustomer;             if (_httpContext == null ||                 _httpContext.Request == null ||                 !_httpContext.Request.IsAuthenticated ||                 !(_httpContext.User.Identity is FormsIdentity))             {                 return null;             }             var formsIdentity = (FormsIdentity)_httpContext.User.Identity;             var customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket);             if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered())                 _cachedCustomer = customer;             return _cachedCustomer;         }         public virtual Customer GetAuthenticatedCustomerFromTicket(FormsAuthenticationTicket ticket)         {             if (ticket == null)                 throw new ArgumentNullException("ticket");             var usernameOrEmail = ticket.UserData;             if (String.IsNullOrWhiteSpace(usernameOrEmail))                 return null;             var customer = _customerSettings.UsernamesEnabled                 ? _customerService.GetCustomerByUsername(usernameOrEmail)                 : _customerService.GetCustomerByEmail(usernameOrEmail);             return customer;         }     }
FormsAuthenticationService类
    FormsAuthenticationService类实现代码分析

            SignOut方法比较简单,主要是调用了FormsAuthentication的退出方法。重点介绍SignIn()和GetAuthenticatedCustomer()方法

            在SignIn()方法中,首先创建一个类型为FormsAuthenticationTicket的ticket,并且将该ticket进行加密,然后将加密后的信息保存到cookie。

            在GetAuthenticatedCustomer()中,如果说已经缓存了当前用户,则直接返回,如果说当前http上下文没有使用Forms验证的话或者验证不存在的话,则直接返回空置。紧接着,获取之前已经保存的ticket,取到ticket之后,根据保存的UserData,获取到已经登录用户的信息。

 

  
1 public enum CustomerLoginResults     {         /// <summary>         /// Login successful         /// </summary>         Successful = 1,         /// <summary>         /// Customer dies not exist (email or username)         /// </summary>         CustomerNotExist = 2,         /// <summary>         /// Wrong password         /// </summary>         WrongPassword = 3,         /// <summary>         /// Account have not been activated         /// </summary>         NotActive = 4,         /// <summary>         /// Customer has been deleted          /// </summary>         Deleted = 5,         /// <summary>         /// Customer not registered          /// </summary>         NotRegistered = 6,     }
CustomerLoginResults枚举类型
  
1 public partial interface ICustomerRegistrationService     {         /// <summary>         /// Validate customer         /// </summary>         /// <param name="usernameOrEmail">Username or email</param>         /// <param name="password">Password</param>         /// <returns>Result</returns>         CustomerLoginResults ValidateCustomer(string usernameOrEmail, string password);     }
ICustomerRegistrationService接口
  
1  public partial class CustomerRegistrationService : ICustomerRegistrationService     {         #region Fields         private readonly ICustomerService _customerService;         private readonly CustomerSettings _customerSettings;         #endregion         #region Ctor         /// <summary>         /// Ctor         /// </summary>         /// <param name="customerService">Customer service</param>         /// <param name="encryptionService">Encryption service</param>         /// <param name="newsLetterSubscriptionService">Newsletter subscription service</param>         /// <param name="localizationService">Localization service</param>         /// <param name="storeService">Store service</param>         /// <param name="rewardPointsSettings">Reward points settings</param>         /// <param name="customerSettings">Customer settings</param>         public CustomerRegistrationService(ICustomerService customerService,              CustomerSettings customerSettings)         {             this._customerService = customerService;             this._customerSettings = customerSettings;         }         #endregion         #region Methods         /// <summary>         /// Validate customer         /// </summary>         /// <param name="usernameOrEmail">Username or email</param>         /// <param name="password">Password</param>         /// <returns>Result</returns>         public virtual CustomerLoginResults ValidateCustomer(string usernameOrEmail, string password)         {             Customer customer;             if (_customerSettings.UsernamesEnabled)                 customer = _customerService.GetCustomerByUsername(usernameOrEmail);             else                 customer = _customerService.GetCustomerByEmail(usernameOrEmail);             if (customer == null)                 return CustomerLoginResults.CustomerNotExist;             string pwd = "";             bool isValid = pwd == customer.Password;             if (!isValid)                 return CustomerLoginResults.WrongPassword;             //save last login date             customer.LastLoginDateUtc = DateTime.UtcNow;             _customerService.UpdateCustomer(customer);             return CustomerLoginResults.Successful;         }         #endregion     }
CustomerRegistrationService

  CustomerRegistrationService类实现代码分析

            在验证用户的方法中还是比较简单的,首先根据用户用户设置,是用户名登录还是邮箱登录,然后根据用户名或者邮箱获取到用户信息,如果用户信息为空的话,则表示用户不存在,否则,则更新登录用户的用户信息。

    nopcommerce项目中实现的用户验证绝非如此简单,它提供了密码加密格式的验证,感兴趣的同学可以下载看一看。

 

  
1 /// <summary>     /// Work context     /// </summary>     public interface IWorkContext     {         /// <summary>         /// Gets or sets the current customer         /// </summary>         Customer CurrentCustomer { get; set; }                  /// <summary>         /// Get or set value indicating whether we're in admin area         /// </summary>         bool IsAdmin { get; set; }     }
IWorkContext接口:该接口主要是提供当前工作环境的信息,比如当前用户信息、当前语言等等,简化版中只提供了当前用户信息
  
1 public partial class WebWorkContext : IWorkContext     {         #region Const         private const string CustomerCookieName = "Nop.customer";         #endregion         #region Fields         private readonly HttpContextBase _httpContext;         private readonly ICustomerService _customerService;         private readonly IAuthenticationService _authenticationService;         private Customer _cachedCustomer;         #endregion         #region Ctor         public WebWorkContext(HttpContextBase httpContext,             ICustomerService customerService,             IAuthenticationService authenticationService,)         {             this._httpContext = httpContext;             this._customerService = customerService;             this._authenticationService = authenticationService;         }         #endregion         #region Utilities         protected virtual HttpCookie GetCustomerCookie()         {             if (_httpContext == null || _httpContext.Request == null)                 return null;             return _httpContext.Request.Cookies[CustomerCookieName];         }         protected virtual void SetCustomerCookie(Guid customerGuid)         {             if (_httpContext != null && _httpContext.Response != null)             {                 var cookie = new HttpCookie(CustomerCookieName);                 cookie.HttpOnly = true;                 cookie.Value = customerGuid.ToString();                 if (customerGuid == Guid.Empty)                 {                     cookie.Expires = DateTime.Now.AddMonths(-1);                 }                 else                 {                     int cookieExpires = 24*365; //TODO make configurable                     cookie.Expires = DateTime.Now.AddHours(cookieExpires);                 }                 _httpContext.Response.Cookies.Remove(CustomerCookieName);                 _httpContext.Response.Cookies.Add(cookie);             }         }                #endregion         #region Properties         /// <summary>         /// Gets or sets the current customer         /// </summary>         public virtual Customer CurrentCustomer         {             get             {                 if (_cachedCustomer != null)                     return _cachedCustomer;                 Customer customer = null;                                  //registered user                 if (customer == null || customer.Deleted || !customer.Active)                 {                     customer = _authenticationService.GetAuthenticatedCustomer();                 }                 //impersonate user if required (currently used for 'phone order' support)                 if (customer != null && !customer.Deleted && customer.Active)                 {                     var impersonatedCustomerId = customer.GetAttribute<int?>(SystemCustomerAttributeNames.ImpersonatedCustomerId);                     if (impersonatedCustomerId.HasValue && impersonatedCustomerId.Value > 0)                     {                         var impersonatedCustomer = _customerService.GetCustomerById(impersonatedCustomerId.Value);                         if (impersonatedCustomer != null && !impersonatedCustomer.Deleted && impersonatedCustomer.Active)                         {                             //set impersonated customer                             _originalCustomerIfImpersonated = customer;                             customer = impersonatedCustomer;                         }                     }                 }                 //load guest customer                 if (customer == null || customer.Deleted || !customer.Active)                 {                     var customerCookie = GetCustomerCookie();                     if (customerCookie != null && !String.IsNullOrEmpty(customerCookie.Value))                     {                         Guid customerGuid;                         if (Guid.TryParse(customerCookie.Value, out customerGuid))                         {                             var customerByCookie = _customerService.GetCustomerByGuid(customerGuid);                             if (customerByCookie != null &&                                 //this customer (from cookie) should not be registered                                 !customerByCookie.IsRegistered())                                 customer = customerByCookie;                         }                     }                 }                 //create guest if not exists                 if (customer == null || customer.Deleted || !customer.Active)                 {                     customer = _customerService.InsertGuestCustomer();                 }                 //validation                 if (!customer.Deleted && customer.Active)                 {                     SetCustomerCookie(customer.CustomerGuid);                     _cachedCustomer = customer;                 }                 return _cachedCustomer;             }             set             {                 SetCustomerCookie(value.CustomerGuid);                 _cachedCustomer = value;             }         }         /// <summary>         /// Get or set value indicating whether we're in admin area         /// </summary>         public virtual bool IsAdmin { get; set; }         #endregion     }
WebWorkContext类:该类实现了IWorkContext接口,提供了web下的工作环境
  WebWorkContext类实现代码分析

            该类的CurrentCustomer属性的实现简化了一部分,我们首先判断用户信息是否已经缓存,如果已经缓存了,则直接返回,如果没有,则需要从FormsAuthenticationService中重新获取用户信息,根据该用户的信息,设置单个用户的cookie。更加详细的实现内容请下载nopcommerce源码。

 

  
1 /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permission">Permission record</param>         /// <returns>true - authorized; otherwise, false</returns>         bool Authorize(PermissionRecord permission);         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permission">Permission record</param>         /// <param name="customer">Customer</param>         /// <returns>true - authorized; otherwise, false</returns>         bool Authorize(PermissionRecord permission, Customer customer);         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permissionRecordSystemName">Permission record system name</param>         /// <returns>true - authorized; otherwise, false</returns>         bool Authorize(string permissionRecordSystemName);         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permissionRecordSystemName">Permission record system name</param>         /// <param name="customer">Customer</param>         /// <returns>true - authorized; otherwise, false</returns>         bool Authorize(string permissionRecordSystemName, Customer customer);
IPermissionService接口
  
1 public partial class PermissionService : IPermissionService     {         #region Constants         /// <summary>         /// Key pattern to clear cache         /// </summary>         private const string PERMISSIONS_PATTERN_KEY = "Nop.permission.";         #endregion         #region Fields         private readonly IRepository<PermissionRecord> _permissionRecordRepository;         private readonly ICustomerService _customerService;         private readonly IWorkContext _workContext;         #endregion         #region Ctor         /// <summary>         /// Ctor         /// </summary>         /// <param name="permissionRecordRepository">Permission repository</param>         /// <param name="customerService">Customer service</param>         /// <param name="workContext">Work context</param>         /// <param name="localizationService">Localization service</param>         /// <param name="languageService">Language service</param>         /// <param name="cacheManager">Cache manager</param>         public PermissionService(IRepository<PermissionRecord> permissionRecordRepository,             ICustomerService customerService,             IWorkContext workContext)         {             this._permissionRecordRepository = permissionRecordRepository;             this._customerService = customerService;             this._workContext = workContext;         }         #endregion         #region Methods         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permission">Permission record</param>         /// <returns>true - authorized; otherwise, false</returns>         public virtual bool Authorize(PermissionRecord permission)         {             return Authorize(permission, _workContext.CurrentCustomer);         }         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permission">Permission record</param>         /// <param name="customer">Customer</param>         /// <returns>true - authorized; otherwise, false</returns>         public virtual bool Authorize(PermissionRecord permission, Customer customer)         {             if (permission == null)                 return false;             if (customer == null)                 return false;             //old implementation of Authorize method             //var customerRoles = customer.CustomerRoles.Where(cr => cr.Active);             //foreach (var role in customerRoles)             //    foreach (var permission1 in role.PermissionRecords)             //        if (permission1.SystemName.Equals(permission.SystemName, StringComparison.InvariantCultureIgnoreCase))             //            return true;             //return false;             return Authorize(permission.SystemName, customer);         }         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permissionRecordSystemName">Permission record system name</param>         /// <returns>true - authorized; otherwise, false</returns>         public virtual bool Authorize(string permissionRecordSystemName)         {             return Authorize(permissionRecordSystemName, _workContext.CurrentCustomer);         }         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permissionRecordSystemName">Permission record system name</param>         /// <param name="customer">Customer</param>         /// <returns>true - authorized; otherwise, false</returns>         public virtual bool Authorize(string permissionRecordSystemName, Customer customer)         {             if (String.IsNullOrEmpty(permissionRecordSystemName))                 return false;             var customerRoles = customer.CustomerRoles.Where(cr => cr.Active);             foreach (var role in customerRoles)                 if (Authorize(permissionRecordSystemName, role))                     //yes, we have such permission                     return true;                          //no permission found             return false;         }         #endregion         #region Utilities         /// <summary>         /// Authorize permission         /// </summary>         /// <param name="permissionRecordSystemName">Permission record system name</param>         /// <param name="customerRole">Customer role</param>         /// <returns>true - authorized; otherwise, false</returns>         protected virtual bool Authorize(string permissionRecordSystemName, CustomerRole customerRole)         {             if (String.IsNullOrEmpty(permissionRecordSystemName))                 return false;             string key = string.Format(PERMISSIONS_ALLOWED_KEY, customerRole.Id, permissionRecordSystemName);             return _cacheManager.Get(key, () =>             {                 foreach (var permission1 in customerRole.PermissionRecords)                     if (permission1.SystemName.Equals(permissionRecordSystemName, StringComparison.InvariantCultureIgnoreCase))                         return true;                 return false;             });         }         #endregion     }
PermissionService类实现代码分析

  PermissionService类实现代码分析

            分析Authorize代码可以知道,首先是要获取当前用户所隶属的所有用户组,然后根据权限名称和用户组判断是否具有某个模块的访问权限。

3.3  相关控制器源代码

PermissionController类:主要是两个登录的Action,通过一下代码可以看出,当用户登录成功之后,需要调用 _authenticationService的登录方法,通过该方法记录已经登录用户的ID

 
1 [NopHttpsRequirement(SslRequirement.Yes)]         public ActionResult Login(bool? checkoutAsGuest)         {             var model = new LoginModel();             model.UsernamesEnabled = _customerSettings.UsernamesEnabled;             model.CheckoutAsGuest = checkoutAsGuest.GetValueOrDefault();             model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage;             return View(model);         }         [HttpPost]         [CaptchaValidator]         public ActionResult Login(LoginModel model, string returnUrl, bool captchaValid)         {             //validate CAPTCHA             if (_captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage && !captchaValid)             {                 ModelState.AddModelError("", _localizationService.GetResource("Common.WrongCaptcha"));             }             if (ModelState.IsValid)             {                 if (_customerSettings.UsernamesEnabled && model.Username != null)                 {                     model.Username = model.Username.Trim();                 }                 var loginResult = _customerRegistrationService.ValidateCustomer(_customerSettings.UsernamesEnabled ? model.Username : model.Email, model.Password);                 switch (loginResult)                 {                     case CustomerLoginResults.Successful:                         {                             var customer = _customerSettings.UsernamesEnabled ? _customerService.GetCustomerByUsername(model.Username) : _customerService.GetCustomerByEmail(model.Email);                             //migrate shopping cart                             _shoppingCartService.MigrateShoppingCart(_workContext.CurrentCustomer, customer, true);                             //sign in new customer                             _authenticationService.SignIn(customer, model.RememberMe);                             //activity log                             _customerActivityService.InsertActivity("PublicStore.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer);                             if (String.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))                                 return RedirectToRoute("HomePage");                                                          return Redirect(returnUrl);                         }                     case CustomerLoginResults.CustomerNotExist:                         ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials.CustomerNotExist"));                         break;                     case CustomerLoginResults.Deleted:                         ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials.Deleted"));                         break;                     case CustomerLoginResults.NotActive:                         ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials.NotActive"));                         break;                     case CustomerLoginResults.NotRegistered:                         ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials.NotRegistered"));                         break;                     case CustomerLoginResults.WrongPassword:                     default:                         ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials"));                         break;                 }             }             //If we got this far, something failed, redisplay form             model.UsernamesEnabled = _customerSettings.UsernamesEnabled;             model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage;             return View(model);         }
View Code

 

   SecurityController类:安全控制器,当用户权限不足时,则展示AccessDenied界面。Permissions是访问控制界面的Action

  1 /// <summary>
  2         /// 拒绝访问
  3         /// </summary>
  4         /// <param name="pageUrl"></param>
  5         /// <returns></returns>
  6         public ActionResult AccessDenied(string pageUrl)
  7         {
  8             var currentCustomer = _workContext.CurrentCustomer;
  9             if (currentCustomer == null || currentCustomer.IsGuest())
 10             {
 11                 _logger.Information(string.Format("Access denied to anonymous request on {0}", pageUrl));
 12                 return View();
 13             }
 14  
 15             _logger.Information(string.Format("Access denied to user #{0} '{1}' on {2}", currentCustomer.Email, currentCustomer.Email, pageUrl));
 16  
 17  
 18             return View();
 19         }
 20  
 21         /// <summary>
 22         /// GET:/Admin/Security/Permissions
 23         /// 获取权限列表
 24         /// </summary>
 25         /// <returns></returns>
 26         public ActionResult Permissions()
 27         {
 28             if (!_permissionService.Authorize(StandardPermissionProvider.ManageAcl))
 29                 return AccessDeniedView();
 30  
 31             var model = new PermissionMappingModel();
 32  
 33             var permissionRecords = _permissionService.GetAllPermissionRecords();
 34             var customerRoles = _customerService.GetAllCustomerRoles(true);
 35             foreach (var pr in permissionRecords)
 36             {
 37                 model.AvailablePermissions.Add(new PermissionRecordModel
 38                 {
 39                     //Name = pr.Name,
 40                     Name = pr.GetLocalizedPermissionName(_localizationService, _workContext),
 41                     SystemName = pr.SystemName
 42                 });
 43             }
 44             foreach (var cr in customerRoles)
 45             {
 46                 model.AvailableCustomerRoles.Add(new CustomerRoleModel
 47                 {
 48                     Id = cr.Id,
 49                     Name = cr.Name
 50                 });
 51             }
 52             foreach (var pr in permissionRecords)
 53                 foreach (var cr in customerRoles)
 54                 {
 55                     bool allowed = pr.CustomerRoles.Count(x => x.Id == cr.Id) > 0;
 56                     if (!model.Allowed.ContainsKey(pr.SystemName))
 57                         model.Allowed[pr.SystemName] = new Dictionary<int, bool>();
 58                     model.Allowed[pr.SystemName][cr.Id] = allowed;
 59                 }
 60  
 61             return View(model);
 62         }
 63  
 64         /// <summary>
 65         /// GET:/Admin/Security/Permissions
 66         /// 提交访问权限
 67         /// </summary>
 68         /// <param name="form"></param>
 69         /// <returns></returns>
 70         [HttpPost, ActionName("Permissions")]
 71         public ActionResult PermissionsSave(FormCollection form)
 72         {
 73             if (!_permissionService.Authorize(StandardPermissionProvider.ManageAcl))
 74                 return AccessDeniedView();
 75  
 76             var permissionRecords = _permissionService.GetAllPermissionRecords();
 77             var customerRoles = _customerService.GetAllCustomerRoles(true);
 78  
 79  
 80             foreach (var cr in customerRoles)
 81             {
 82                 string formKey = "allow_" + cr.Id;
 83                 var permissionRecordSystemNamesToRestrict = form[formKey] != null ? form[formKey].Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>();
 84  
 85                 foreach (var pr in permissionRecords)
 86                 {
 87  
 88                     bool allow = permissionRecordSystemNamesToRestrict.Contains(pr.SystemName);
 89                     if (allow)
 90                     {
 91                         if (pr.CustomerRoles.FirstOrDefault(x => x.Id == cr.Id) == null)
 92                         {
 93                             pr.CustomerRoles.Add(cr);
 94                             _permissionService.UpdatePermissionRecord(pr);
 95                         }
 96                     }
 97                     else
 98                     {
 99                         if (pr.CustomerRoles.FirstOrDefault(x => x.Id == cr.Id) != null)
100                         {
101                             pr.CustomerRoles.Remove(cr);
102                             _permissionService.UpdatePermissionRecord(pr);
103                         }
104                     }
105                 }
106             }
107  
108             SuccessNotification(_localizationService.GetResource("Admin.Configuration.ACL.Updated"));
109             return RedirectToAction("Permissions");
110         }
View Code

 

3.4  相关View源代码

            PermissionMappingModel:访问控制管理界面模型

1 public partial class PermissionMappingModel : BaseNopModel     {         public PermissionMappingModel()         {             AvailablePermissions = new List<PermissionRecordModel>();             AvailableCustomerRoles = new List<CustomerRoleModel>();             Allowed = new Dictionary<string, IDictionary<int, bool>>();         }         public IList<PermissionRecordModel> AvailablePermissions { get; set; }         public IList<CustomerRoleModel> AvailableCustomerRoles { get; set; }         //[permission system name] / [customer role id] / [allowed]         public IDictionary<string, IDictionary<int, bool>> Allowed { get; set; }     }
View Code

 

Permissions.cshtml:访问控制管理界面

1 @model PermissionMappingModel
2 @{                    //page title     ViewBag.Title = T("Admin.Configuration.ACL").Text;
3 }
4 @using (Html.BeginForm())
5 {     @Html.AntiForgeryToken()     <div class="section-header">         <div class="title">             <img src="@Url.Content("~/Administration/Content/images/ico-configuration.png")" alt="" />             @T("Admin.Configuration.ACL")         </div>         <div class="options">             <input type="submit" name="save" class="k-button" value="@T("Admin.Common.Save")" />         </div>     </div>          <table class="adminContent">         <tr>             <td>                 @if (Model.AvailablePermissions.Count == 0)                 {                     <text>No permissions defined</text>                 }                 else if (Model.AvailableCustomerRoles.Count == 0)                 {                     <text>No customer roles available</text>                 }                 else                 {                     <script type="text/javascript">                         $(document).ready(function () {                                         @foreach (var cr in Model.AvailableCustomerRoles)                             {                                 <text>                                 $('#selectall-@(cr.Id)').click(function () {                                     $('.allow_@(cr.Id)').attr('checked', $(this).is(':checked')).change();                                     });                                 </text>                             }                         });                     </script>                     <table class="tablestyle" cellspacing="0" rules="all" border="1" style="width: 100%;                         border-collapse: collapse;">                         <tbody>                             <tr class="headerstyle">                                 <th scope="col">                                     <strong>@T("Admin.Configuration.ACL.Permission")</strong>                                 </th>                                 @foreach (var cr in Model.AvailableCustomerRoles)                                 {                                     <th scope="col">                                         <strong>@cr.Name</strong>                                         <input type="checkbox" id="selectall-@(cr.Id)" />                                     </th>                                 }                             </tr>                             @{                                 bool altRow = true;                             }                             @foreach (var pr in Model.AvailablePermissions)                             {                                 altRow = !altRow;                                 <tr class="@(altRow ? "altrowstyle" : "rowstyle")">                                     <td>                                         <span>@pr.Name</span>                                     </td>                                     @foreach (var cr in Model.AvailableCustomerRoles)                                     {                                         var allowed = Model.Allowed.ContainsKey(pr.SystemName) && Model.Allowed[pr.SystemName][cr.Id];                                         <td>                                             <input class="allow_@(cr.Id)" class="allow_@(cr.Id)" type="checkbox" value="@(pr.SystemName)" name="allow_@(cr.Id)" @(allowed ? " checked=checked" : null) />                                         </td>                                     }                                 </tr>                             }                         </tbody>                     </table>                 }             </td>         </tr>     </table>
6  
7 }
View Code

 

4.  总结

     通过对nopcommerce项目中的访问控制代码的分析,使得我对MVC4下的用户验证的实现有了进一步的了解:通过FormsAuthentication和HttpCookie来进行用户验证以及具体的实现过程。

     该项目中的访问控制也是值得学习的,使得权限记录和用户组发送多对多的关系,当能查询到某个用户组含有对应的访问权限,则表示该用户组对这个模块有访问权限。

     通过学习nopcommerce项目代码,我也编写了一个小Demo:AclDemo,该项目将在下一篇进行分析和源代码下载,敬请期待,感兴趣的可以关注我。

posted @ 2015-03-18 16:24  诸葛小亮  阅读(2362)  评论(0编辑  收藏  举报