Hi I'm having trouble passing through Claims identity values directly into the view. I have a create a Security.cs file and i would like access through values inside the View. For Example, i expect to return #CurrentUser.DisplayName but unfortunately #CurrentUser does not exist is the current context. This has baffled me to be honest, Any ideas please?
Also as an edit: I can pull values through to my controller no problem.
Below is my Security Controller:
[HttpPost]
public ActionResult CheckUser(string returnURL)
{
ViewBag.ReturnURL = returnURL;
GRATT.BLL.GratManager gm = new GRATT.BLL.GratManager();
string username = Request.Form["username"];
string password = Request.Form["password"];
GRATT.DTO.AppUser au = gm.GetUser(username, password);
if (au != null)
{
if (Membership.ValidateUser(Request.Form["username"], Request.Form["password"]))
{
ClaimsIdentity identity = new ClaimsIdentity(new[]
{
new Claim("Username", au.Username.ToString()),
new Claim("UserId", au.UserId.ToString()),
new Claim("DisplayName", (au.Name.Forename ?? "") +" "+ (au.Name.Surname ?? "")),
new Claim("SiteCode", au.Site.ToLower().ToString())
}, "GratAuditTool_Authentication");
foreach (GRATT.DTO.UserRole r in au.Roles)
{
identity.AddClaim(new Claim("Role", r.Role.Name));
}
var ctx = Request.GetOwinContext();
var authManager = ctx.Authentication;
authManager.SignIn(identity);
return RedirectToAction("Index", "Home");
}
}
return RedirectToAction("Login", "Security");
}
And below is my Security.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Claims;
using System.Web.Mvc;
namespace GrattAuditTool.UI
{
public class GratAuditToolClaimsPrincipal : ClaimsPrincipal
{
public GratAuditToolClaimsPrincipal(ClaimsPrincipal p) : base(p)
{
}
public string DisplayName
{
get
{
return FindFirst("DisplayName").Value;
}
}
public string UserID
{
get
{
return FindFirst("UserID").Value;
}
}
public string Initials
{
get
{
return FindFirst("Initials").Value;
}
}
public Boolean IsAdmin
{
get
{
return Convert.ToBoolean(FindFirst("Admin").Value);
}
}
public string SiteCode
{
get
{
return FindFirst("SiteCode").Value;
}
}
public List<string> Roles
{
get
{
List<string> roles = new List<string>();
foreach (string s in FindAll("Role").Select(x => x.Value))
{
roles.Add(s);
}
return roles;
}
}
}
public abstract class GratAuditToolController : Controller
{
public GratAuditToolClaimsPrincipal CurrentUser
{
get
{
return new GratAuditToolClaimsPrincipal(User as ClaimsPrincipal);
}
}
}
public abstract class GratAuditToolViewPage<TModel> : WebViewPage<TModel>
{
public GratAuditToolClaimsPrincipal CurrentUser
{
get
{
return new GratAuditToolClaimsPrincipal(User as ClaimsPrincipal);
}
}
}
public abstract class GratAuditToolViewPage : GratAuditToolViewPage<dynamic>
{
}
}
Related
I am developing an ASP.NET Core 6 MVC project and am getting the error which is shown in this screenshot:
This is my homework so any help would be appreciated.
I tried to change controller and repository but nothing changed. Code is below - ClubController:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using webHomework.Data;
using webHomework.Interfaces;
using webHomework.Models;
using webHomework.ViewModels;
namespace webHomework.Controllers
{
public class ClubController : Controller
{
private readonly IClubRepository _clubRepository;
private readonly IPhotoService _photoService;
public ClubController(IClubRepository clubRepository, IPhotoService photoService)
{
_clubRepository = clubRepository;
_photoService = photoService;
}
public async Task<IActionResult> Index()
{
IEnumerable<Club> clubs = await _clubRepository.GetAll();
return View(clubs);
}
public async Task<IActionResult> Detail(int id)
{
Club club = await _clubRepository.GetByIdAsync(id);
return View(club);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create(CreateClubViewModel clubVM)
{
if (ModelState.IsValid)
{
var result = await _photoService.AddPhotoAsync(clubVM.Image);
var club = new Club
{
Title = clubVM.Title,
Description = clubVM.Description,
Image = result.Url.ToString(),
Address = new Address
{
Street = clubVM.Address.Street,
City = clubVM.Address.City,
State = clubVM.Address.State,
}
};
_clubRepository.Add(club);
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("", "Photo upload failed");
}
return View(clubVM);
}
}
}
ClubRepository:
using Microsoft.EntityFrameworkCore;
using webHomework.Data;
using webHomework.Interfaces;
using webHomework.Models;
namespace webHomework.Repository
{
public class ClubRepository : IClubRepository
{
private readonly ApplicationDbContext _context;
public ClubRepository (ApplicationDbContext context)
{
_context = context;
}
public bool Add(Club club)
{
_context.Add(club);
return Save();
}
public bool Delete(Club club)
{
_context.Remove(club);
return Save();
}
public async Task<IEnumerable<Club>> GetAll()
{
return await _context.Clubs.ToListAsync();
}
public async Task<Club> GetByIdAsync(int id)
{
return await _context.Clubs.Include(i => i.Address).FirstOrDefaultAsync(i => i.Id == id);
}
public async Task<IEnumerable<Club>> GetClubByCity(string city)
{
return await _context.Clubs.Where(c => c.Address.City.Contains(city)).ToListAsync();
}
public bool Save()
{
var saved = _context.SaveChanges();
return saved > 0 ? true : false;
}
public bool Update(Club club)
{
_context.Update(club);
return Save();
}
}
}
Declare your int property which is mapped to database number field as nullable with int?.
I've added a few specific Properties to the ApplicationUser of the standart project.
some of the added Properties are of custom classes.
Since i use EntityFramework, it creates a dbtable for users and one for each custom class.
i added the Properties to my ManageController and Views and adding these Properties to the specific dbtable works, but i cant access them. in the dbo.AspNetUsers there is a column added, that is called after the attribute + ID (In my example "NameID").
Now if i am loading the user in my ManageController, every normal Attribute is loaded, but the custom ones are null.
My Question is, how can i load the custom objects (that are really stored in the other table).
ApplicationUser.cs:
namespace refProject.Models
{
public class ApplicationUser : IdentityUser
{
public Name Name { get; set; }
}
}
ManageController.cs
//other usings
using refProject.Models;
using refProject.Models.ManageViewModels;
namespace refProject.Controllers
{
[Authorize]
public class ManageController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
//other managers
public ManageController(
UserManager<ApplicationUser> userManager,
//other managers
)
{
_userManager = userManager;
//other managers
}
//
// GET: /Manage/Index
[HttpGet]
public async Task<IActionResult> Index(ManageMessageId? message = null)
{
ViewData["StatusMessage"] =
message == ManageMessageId.ChangeNameSuccess ? "Your name has been changed."
: message == ManageMessageId.SetNameSuccess ? "Your name has been set."
: "";
var user = await GetCurrentUserAsync();
if (user == null)
{
return View("Error");
}
var model = new IndexViewModel
{
//other Properties
//
//
// THIS ONE IS NULL
//
//
Name = user.Name
//other Properties
};
return View(model);
}
// GET: /Manage/ChangeName
[HttpGet]
public IActionResult ChangeName()
{
return View();
}
//
// POST: /Manage/ChangeName
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangeName(ChangeNameViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var user = await GetCurrentUserAsync();
if(user != null)
{
Name NewName = new Name();
NewName.FirstName = model.NewFirstName;
NewName.LastName = model.NewLastName;
user.Name = NewName;
IdentityResult result = await _userManager.UpdateAsync(user);
if (result.Succeeded)
{
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangeNameSuccess });
}
AddErrors(result);
return View(model);
}
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
}
//
// GET: /Manage/SetName
[HttpGet]
public IActionResult SetName()
{
return View();
}
//
// POST: /Manage/SetName
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SetName(SetNameViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var user = await GetCurrentUserAsync();
if(user != null)
{
Name NewName = new Name();
NewName.FirstName = model.NewFirstName;
NewName.LastName = model.NewLastName;
user.Name = NewName;
IdentityResult result = await _userManager.UpdateAsync(user);
if(result.Succeeded)
{
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetNameSuccess });
}
AddErrors(result);
return View(model);
}
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
}
#region Helpers
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
public enum ManageMessageId
{
Error,
ChangeNameSuccess,
SetNameSuccess,
}
private Task<ApplicationUser> GetCurrentUserAsync()
{
return _userManager.GetUserAsync(HttpContext.User);
}
#endregion
}
}
Name.cs
namespace refProject.Models
{
public class Name
{
public int ID { get; set; }
public string fTitle { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string lTitle { get; set; }
public override string ToString()
{
return fTitle + " " + FirstName + " " + LastName + " " + lTitle;
}
}
}
That is a known issue. It is not considered a bug, but rather a design decision.
The recommended way is to access the user through DbContext rather than from the UserManager implementation.
"Just to add a bit more detail: as a performance optimization ASP.NET Core Identity currently only loads the entities related to a user or a role as needed to satisfy API calls. I.e. it won't load related entities (not even the built-in ones) eagerly on a method call like such as FindByName() because the find methods are only required to return the root.
At this point issuing queries against the DbContext is the recommended
way to load related data. If you want to abstract this from the
application code you can extend both the Identity store and manager
classes to add methods to retrieve and return your custom related
data."
Comment link
You could change your GetCurrentUserAsync method as follows:
private ApplicationUser GetCurrentUserAsync()
{
return _userManager.Users.Include(x => x.Name).FirstOrDefault(x => x.Id == _userManager.GetUserId(User));
}
I am using ASP.Net Identity to create an app with roles based authentication. I want to create some custom roles. When I do that I get the following exception. But I'm unable to figure what's wrong here. Since I'm new to this Please do help me out. Thanks in advance.
I get the exception in
var appRoleManager = new ApplicationRoleManager(new RoleStore(context.Get()));
which is in the ApplicationRoleManager.cs class
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EasyMaintain.SecurityWebAPI
{
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
//create instances for each request
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
var appRoleManager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<AuthContext>()));
return appRoleManager;
}
}
}
The RoleModel.cs
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Routing;
namespace EasyMaintain.SecurityWebAPI.Models
{
public class RoleModel
{
private UrlHelper _UrlHelper;
private ApplicationUserManager _AppUserManager;
public RoleModel(HttpRequestMessage request, ApplicationUserManager appUserManager)
{
_UrlHelper = new UrlHelper(request);
_AppUserManager = appUserManager;
}
public RoleReturnModel Create(IdentityRole appRole)
{
return new RoleReturnModel
{
Url = _UrlHelper.Link("GetRoleById", new { id = appRole.Id }),
Id = appRole.Id,
Name = appRole.Name
};
}
}
public class RoleReturnModel
{
public string Url { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
}
The RoleController.cs
using EasyMaintain.SecurityWebAPI.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using static EasyMaintain.SecurityWebAPI.Models.RoleBindingModels;
namespace EasyMaintain.SecurityWebAPI.Controllers
{
[Authorize(Roles = "SuperAdmin")]
[RoutePrefix("api/roles")]
public class RolesController : BaseApiController
{
// GET api/roles
[Route("{id:guid}", Name = "GetRoleById")]
public async Task<IHttpActionResult> GetRole(string Id)
{
var role = await this.AppRoleManager.FindByIdAsync(Id);
if (role != null)
{
return Ok(TheModelFactory.Create(role));
}
return NotFound();
}
//GET api/roles/5
[Route("", Name = "GetAllRoles")]
public IHttpActionResult GetAllRoles()
{
var roles = this.AppRoleManager.Roles;
return Ok(roles);
}
// POST api/roles
[Route("create")]
[HttpPost]
public async Task<IHttpActionResult> Create(RoleBindingModels model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var role = new IdentityRole { Name = model.Name };
var result = await this.AppRoleManager.CreateAsync(role);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
Uri locationHeader = new Uri(Url.Link("GetRoleById", new { id = role.Id }));
return Created(locationHeader, TheModelFactory.Create(role));
}
[Route("{id:guid}")]
public async Task<IHttpActionResult> DeleteRole(string Id)
{
var role = await this.AppRoleManager.FindByIdAsync(Id);
if (role != null)
{
IdentityResult result = await this.AppRoleManager.DeleteAsync(role);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
return NotFound();
}
[Route("ManageUsersInRole")]
public async Task<IHttpActionResult> ManageUsersInRole(UsersInRoleModel model)
{
var role = await this.AppRoleManager.FindByIdAsync(model.Id);
if (role == null)
{
ModelState.AddModelError("", "Role does not exist");
return BadRequest(ModelState);
}
foreach (string user in model.EnrolledUsers)
{
var appUser = await this.AppUserManager.FindByIdAsync(user);
if (appUser == null)
{
ModelState.AddModelError("", String.Format("User: {0} does not exists", user));
continue;
}
if (!this.AppUserManager.IsInRole(user, role.Name))
{
IdentityResult result = await this.AppUserManager.AddToRoleAsync(user, role.Name);
if (!result.Succeeded)
{
ModelState.AddModelError("", String.Format("User: {0} could not be added to role", user));
}
}
}
foreach (string user in model.RemovedUsers)
{
var appUser = await this.AppUserManager.FindByIdAsync(user);
if (appUser == null)
{
ModelState.AddModelError("", String.Format("User: {0} does not exists", user));
continue;
}
IdentityResult result = await this.AppUserManager.RemoveFromRoleAsync(user, role.Name);
if (!result.Succeeded)
{
ModelState.AddModelError("", String.Format("User: {0} could not be removed from role", user));
}
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok();
}
}
}
Check that in Startup.Auth, the RoleManager is referenced like this:
public void ConfigureAuth(IAppBuilder app)
{
// Add this reference
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
}
Make sure your Controller includes this constructor:
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager { get { return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>(); } private set { _roleManager = value; } }
And make sure you dispose of the Role Manager in your Controller like this:
protected override void Dispose(bool disposing)
{
if (disposing && RoleManager != null)
{
RoleManager.Dispose();
RoleManager = null;
}
if (disposing)
{
context.Dispose();
}
base.Dispose(disposing);
}
When you try to perform an action, for example: login on the page, an error: Cannot drop database "Practice" because it is currently in use.
What's the matter?
"Sorry for my bad english"
Providers:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using CustomRoleProviderApp;
using Models;
using System.Web.Security;
namespace CustomRoleProviderApp.Providers
{
public class CustomRoleProvider : RoleProvider
{
public override string[] GetRolesForUser(string username)
{
string[] role = new string[] { };
using (PracticeDB db = new PracticeDB())
{
// Получаем пользователя
Users user = db.Users.FirstOrDefault(u => u.Name == username);
if (user != null)
{
// получаем роль
Models.Roles userRole = db.Roles.Find(user.RoleID);
if (userRole != null)
role = new string[] { userRole.RoleName };
}
}
return role;
}
public override void CreateRole(string roleName)
{
Models.Roles newRole = new Models.Roles() { RoleName = roleName };
PracticeDB db = new PracticeDB();
db.Roles.Add(newRole);
db.SaveChanges();
}
public override bool IsUserInRole(string username, string roleName)
{
bool outputResult = false;
// Находим пользователя
using (PracticeDB db = new PracticeDB())
{
// Получаем пользователя
Users user = db.Users.FirstOrDefault(u => u.Name == username);
if (user != null)
{
// получаем роль
Models.Roles userRole = db.Roles.Find(user.RoleID);
//сравниваем
if (userRole != null && userRole.RoleName == roleName)
outputResult = true;
}
}
return outputResult;
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override string ApplicationName
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
Model Roles:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace Models
{
public partial class Roles
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Roles()
{
this.Users = new HashSet<Users>();
}
public int RoleID { get; set; }
public string RoleName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Users> Users { get; set; }
}
public class UserDBRoles : DropCreateDatabaseAlways<PracticeDB>
{
protected override void Seed(PracticeDB db)
{
db.Roles.Add(new Roles { RoleID = 1, RoleName = "Admin" });
db.Roles.Add(new Roles { RoleID = 2, RoleName = "User" });
db.Users.Add(new Users
{
UserID= 3,
Name = "Admin",
Password = "123456",
FirstName = "Admin",
LastName = "Adminov",
MiddleName = "Adminovich",
Email = "administratorya#gamil.com",
RoleID = 1
});
base.Seed(db);
}
}
}
Global.asax
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Models
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
Database.SetInitializer(new UserDBRoles());
}
}
}
if you delete a row Database.SetInitializer(new UserDBRoles());then no error, the user is authenticated.
Question Summary: In ASP.NET MVC, is there a clean way to prevent a specific user or role from accessing an action?
Obviously, the following would allow roles Admin and Editor to access the entire controller.
[Authorize(Roles = "Admin, Editor")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
}
If I only wanted the Admin role to have access to the About action, I could do the following:
[Authorize(Roles = "Admin, Editor")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[Authorize(Roles = "Admin")] // this will take precedence over the controller's authorization
public ActionResult About()
{
return View();
}
}
Is there a way to accomplish this without listing every single role that needs access, and only specifying the roles that should be prevented from having access?
Create your own blacklist class just like this one:
public class Blacklist : AuthorizeAttribute {
private List<string> RolesList;
public string Roles {
get {
string roles = "";
if (RolesList!= null && RolesList.Count > 0) {
int counter = 0;
foreach (string role in RolesList) {
counter++;
if (counter == RolesList.Count)
roles = role;
else
roles += role + ",";
}
}
return roles;
}
set {
RolesList = new List<string>();
string[] roles = value.Split(',');
foreach (string role in roles) {
RolesList.Add(role);
}
}
}
//constructor
public Blacklist () {
RolesList = new List<string>();
}
protected override bool AuthorizeCore(HttpContextBase httpContext) {
bool result = true;
if (httpContext == null) {
throw new ArgumentNullException("httpContext");
}
foreach (string role in RolesList) {
if (httpContext.User.IsInRole(role)) {
result = false;
break;
}
}
return result;
}
}
Now you are going to block the roles you want:
[Authorize]
[Blacklist (Roles = "Admin", "Editor")]
public ActionResult Index() {
return View();
}
Here is the code for the class I used to solve this problem. It derives heavily from AuthorizeAttribute, and will allow any authenticated user through who does not match the specifications set by the parameters.
(Note that the important method is AuthorizeCore - everything else is essentially copied or inherited from AuthorizeAttribute)
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class BlackListAttribute : AuthorizeAttribute
{
private static readonly string[] _emptyArray = new string[0];
private string _roles;
private string _users;
private string[] _rolesSplit = _emptyArray;
private string[] _usersSplit = _emptyArray;
public new string Roles
{
get { return _roles ?? String.Empty; }
set
{
_roles = value;
_rolesSplit = SplitString(value);
}
}
public new string Users
{
get { return _users ?? String.Empty; }
set
{
_users = value;
_usersSplit = SplitString(value);
}
}
// This is the important part. Everything else is either inherited from AuthorizeAttribute or, in the case of private or internal members, copied from AuthorizeAttribute.
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && _usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && _rolesSplit.Any(user.IsInRole))
{
return false;
}
return true;
}
internal static string[] SplitString(string original)
{
if (String.IsNullOrEmpty(original))
{
return _emptyArray;
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !String.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
You can use it on controllers or actions like any other AuthorizeAttribute:
[Authorize(Roles = "Admin, Editor")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[BlackList(Roles = "Editor")]
public ActionResult About()
{
return View();
}
}