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,該項目將在下一篇進行分析和源代碼下載,敬請期待,感興趣的能夠關注我。

相關文章
相關標籤/搜索