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

目录javascript

    1.  介绍html

    2.  UMLjava

        2.1  实体类UML图web

        2.2  业务相关UML图redis

    3.  核心代码分析缓存

        3.1  实体类源代码安全

        3.2  业务相关源代码cookie

     3.3  相关控制器源代码mvc

        3.4  相关View源代码app

    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,该项目将在下一篇进行分析和源代码下载,敬请期待,感兴趣的能够关注我。

相关文章
相关标签/搜索