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

时间:2024-06-22 18:08:08

目录

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,该项目将在下一篇分析以及提供源代码。

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

图1-1

2.  UML

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

2.1  实体类UML图

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

2.2  业务相关UML图

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

3.  核心代码分析

3.1  实体类源代码

  Customer类
  
 /// <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类

  
 /// <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  业务相关源代码

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

ICustomerService接口

 /// <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类

 public partial interface IAuthenticationService      {         void SignIn(Customer customer, bool createPersistentCookie);         void SignOut();         Customer GetAuthenticatedCustomer();     }

IAuthenticationService接口

 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,获取到已经登录用户的信息。

  
 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枚举类型

  
 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接口

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

  
 /// <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接口:该接口主要是提供当前工作环境的信息,比如当前用户信息、当前语言等等,简化版中只提供了当前用户信息

  
 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源码。

  
 /// <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接口

  
 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

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

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

 /// <summary>
/// 拒绝访问
/// </summary>
/// <param name="pageUrl"></param>
/// <returns></returns>
public ActionResult AccessDenied(string pageUrl)
{
var currentCustomer = _workContext.CurrentCustomer;
if (currentCustomer == null || currentCustomer.IsGuest())
{
_logger.Information(string.Format("Access denied to anonymous request on {0}", pageUrl));
return View();
} _logger.Information(string.Format("Access denied to user #{0} '{1}' on {2}", currentCustomer.Email, currentCustomer.Email, pageUrl)); return View();
} /// <summary>
/// GET:/Admin/Security/Permissions
/// 获取权限列表
/// </summary>
/// <returns></returns>
public ActionResult Permissions()
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageAcl))
return AccessDeniedView(); var model = new PermissionMappingModel(); var permissionRecords = _permissionService.GetAllPermissionRecords();
var customerRoles = _customerService.GetAllCustomerRoles(true);
foreach (var pr in permissionRecords)
{
model.AvailablePermissions.Add(new PermissionRecordModel
{
//Name = pr.Name,
Name = pr.GetLocalizedPermissionName(_localizationService, _workContext),
SystemName = pr.SystemName
});
}
foreach (var cr in customerRoles)
{
model.AvailableCustomerRoles.Add(new CustomerRoleModel
{
Id = cr.Id,
Name = cr.Name
});
}
foreach (var pr in permissionRecords)
foreach (var cr in customerRoles)
{
bool allowed = pr.CustomerRoles.Count(x => x.Id == cr.Id) > ;
if (!model.Allowed.ContainsKey(pr.SystemName))
model.Allowed[pr.SystemName] = new Dictionary<int, bool>();
model.Allowed[pr.SystemName][cr.Id] = allowed;
} return View(model);
} /// <summary>
/// GET:/Admin/Security/Permissions
/// 提交访问权限
/// </summary>
/// <param name="form"></param>
/// <returns></returns>
[HttpPost, ActionName("Permissions")]
public ActionResult PermissionsSave(FormCollection form)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageAcl))
return AccessDeniedView(); var permissionRecords = _permissionService.GetAllPermissionRecords();
var customerRoles = _customerService.GetAllCustomerRoles(true); foreach (var cr in customerRoles)
{
string formKey = "allow_" + cr.Id;
var permissionRecordSystemNamesToRestrict = form[formKey] != null ? form[formKey].Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); foreach (var pr in permissionRecords)
{ bool allow = permissionRecordSystemNamesToRestrict.Contains(pr.SystemName);
if (allow)
{
if (pr.CustomerRoles.FirstOrDefault(x => x.Id == cr.Id) == null)
{
pr.CustomerRoles.Add(cr);
_permissionService.UpdatePermissionRecord(pr);
}
}
else
{
if (pr.CustomerRoles.FirstOrDefault(x => x.Id == cr.Id) != null)
{
pr.CustomerRoles.Remove(cr);
_permissionService.UpdatePermissionRecord(pr);
}
}
}
} SuccessNotification(_localizationService.GetResource("Admin.Configuration.ACL.Updated"));
return RedirectToAction("Permissions");
}

3.4  相关View源代码

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

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

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

 @model PermissionMappingModel
@{ //page title ViewBag.Title = T("Admin.Configuration.ACL").Text;
}
@using (Html.BeginForm())
{ @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> }

4.  总结

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

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

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