ASP.NET MVC Blacklist for Roles/Users - c#

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

Related

Cant pull data through directly to the view MVC Claims Identity

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

how to redirect from ActionFilterAttribute requests with querystring

I have to redirect any requests to canonical urls. To solve this task i use derived ActionFilterAttribute like code bellow:
public class CheckToRedirectFilterAttribute : ActionFilterAttribute
{
public bool ExactUrl { get; set; } = true;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
ActionResult redirect = filterContext.RouteData.RedirectToNewMap();
if (redirect == null && this.ExactUrl) {
var urlHelper = new UrlHelper(filterContext.RequestContext);
var routeValues = filterContext.RouteData.Values;
foreach (var a in filterContext.ActionParameters)
{
if (!routeValues.ContainsKey(a.Key))
routeValues.Add(a.Key, a.Value);
}
var canonicUrl = urlHelper.Action(filterContext.ActionDescriptor.ActionName, filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.RouteData.Values);
if (filterContext.HttpContext.Request.RawUrl.ToLower() != canonicUrl)
redirect = new RedirectResult(canonicUrl.ToLower());
}
if (redirect != null)
{
filterContext.Result = redirect;
}
}
}
And then I use this attribute on action methods:
public class HomeController : Controller
{
[CheckToRedirectFilter]
public ActionResult Index()
{
return View();
}
}

OverrideAuthorization attribute in .NETCore

In the controller code below, only users who are in the "Administrator" role can access the GetData() action method, because of the controller-level AuthorizeAttribute. But I also want users who only are in "Manager" role to have access to the GetData() action method.
[Authorize(Roles = "Administrator")]
Public class AdminController : Controller
{
[Authorize(Roles = "Administrator, Manager")]
public IActionResult GetData()
{
}
}
Is there an option like OverrideAuthorization attribute available in .NET Core framework to achieve this requirement?
Was able to find a solution after long time of analysis on the Authorization assemblies.
In the startup.cs file, add the Authorization as follows:
services.AddAuthorization(options =>
{
var roles = new List<string>{ Role.Administrator, Role.Manager};
var requirement =
new List<IAuthorizationRequirement> {new AdminManagerAuthorizationOverrideOthers(roles) };
var sharedAuthentication =
new AuthorizationPolicy(requirement,
new List<string>());
options.AddPolicy(name: "AdminManager", policy: sharedAuthentication);
options.AddPolicy(name: "Administrator", configurePolicy: policy => policy.RequireAssertion(e =>
{
if (e.Resource is AuthorizationFilterContext afc)
{
var noPolicy = afc.Filters.OfType<AuthorizeFilter>().Any(p =>
p.Policy.Requirements.Count == 1 &&
p.Policy.Requirements.Single() is AdminManagerAuthorizationOverrideOthers);
if (noPolicy)
return true;
}
return e.User.IsInRole(Role.Administrator);
}));
});
Create a class in any namespace that Inherits "RolesAuthorizationRequirement" from "Microsoft.AspNetCore.Authorization.Infrastructure" namespace as follows:
public class AdminManagerAuthorizationOverrideOthers : RolesAuthorizationRequirement
{
public AdminManagerAuthorizationOverrideOthers(IEnumerable<string> allowedRoles) : base(allowedRoles)
{
}
}
Then, decorate the controller and action method as follows:
[Authorize(Policy = "Administrator")]
Public class AdminController : Controller
{
public IActionResult GetData()
{
}
[Authorize(Policy = "AdminManager")]
public IActionResult AdministratorOnly()
{
}
}
Ideally, you want to narrow down the restriction to Action Method, because in Controller Initialization step, it checks Controller's Authorize filter first before Action filters.
[Authorize(Roles = "Administrator, Manager")]
Public class AdminController : Controller
{
public IActionResult GetData()
{
}
[Authorize(Roles = "Administrator")]
public IActionResult AdministratorOnly()
{
}
}
In ASP.NET Core 2.1 you can do it. Check this: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1
You can also lock down a controller but allow anonymous,
unauthenticated access to individual actions.
[Authorize(Roles = "Admin,Employee")] // admin or employee
public class XController : Controller
{
[Authorize(Roles = "Admin")] // only admin
public ActionResult ActionX() { ... }
[AllowAnonymous] // anyone
public ActionResult ActionX() { ... }
}
All above is right, i just want to give a full example easy for all
My case is Asp.Net Core 3.1
Startup.js (ConfigureServices):
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.User.RequireUniqueEmail = false; // óíèêàëüíûé email
config.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -._#+";
config.SignIn.RequireConfirmedEmail = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<UserManager<ApplicationUser>>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultTokenProviders();
services.AddAuthorization(options =>
{
options.AddPolicy("User", policy => {
policy.RequireClaim("User");
});
options.AddPolicy("Admin", policy => {
policy.RequireRole("Admin");
});
});
services.AddScoped<IAuthorizationHandler, RolesAuthorizationHandler>();
Startup.js (Configure):
app.UseAuthentication();
app.UseAuthorization();
Controller:
[Authorize(Policy = "Admin")]
public class RoleController : Controller
Handler-Example:
public class RolesAuthorizationHandler : AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationHandler
{
private readonly RoleManager<IdentityRole> _roleManager;
private readonly UserManager<ApplicationUser> _userManager;
public RolesAuthorizationHandler(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
RolesAuthorizationRequirement requirement)
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
var validRole = false;
if (requirement.AllowedRoles == null ||
requirement.AllowedRoles.Any() == false)
{
validRole = true;
}
else
{
var claims = context.User.Claims;
//var userName = claims.FirstOrDefault(c => c.Type == "UserName").Value;
var allowedRoles = requirement.AllowedRoles;
var loggedInUserTask = _userManager.GetUserAsync(context.User);
loggedInUserTask.Wait();
var user = loggedInUserTask.Result;
var roles = _userManager.GetRolesAsync(user);
roles.Wait();
var roleList = roles.Result;
validRole = roleList.Where(p => allowedRoles.Contains(p.ToString())).Any();
}
if (validRole)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
}
I While updating a project that used to exist, I moved the old user table to the user table in the new identity database. Later, I defined roles at the table level for them, and with the RoleManager I wrote in this way, I left his next administration to the step. Quite successful. In my case, many people probably updated their old projects. However, I did not have such a post and wanted to share it.
The following section is for them:
public class RoleAssignViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public bool HasAssign { get; set; }
}
public class RoleViewModel
{
[Required(ErrorMessage = "Fill the role.")]
[Display(Name = "Role Name")]
public string Name { get; set; }
}
[Authorize(Policy = "Admin")]
public class RoleController : Controller
{
private readonly RoleManager<IdentityRole> _roleManager;
private readonly UserManager<ApplicationUser> _userManager;
public RoleController(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
public async Task<IActionResult> RoleAssign(string id)
{
ApplicationUser user = await _userManager.FindByIdAsync(id);
List<IdentityRole> allRoles = _roleManager.Roles.ToList();
List<string> userRoles = await _userManager.GetRolesAsync(user) as List<string>;
List<RoleAssignViewModel> assignRoles = new List<RoleAssignViewModel>();
allRoles.ForEach(role => assignRoles.Add(new RoleAssignViewModel
{
HasAssign = userRoles.Contains(role.Name),
RoleId = role.Id,
RoleName = role.Name
}));
return View(assignRoles);
}
[HttpPost]
public async Task<ActionResult> RoleAssign(List<RoleAssignViewModel> modelList, string id)
{
ApplicationUser user = await _userManager.FindByIdAsync(id);
foreach (RoleAssignViewModel role in modelList)
{
if (role.HasAssign)
await _userManager.AddToRoleAsync(user, role.RoleName);
else
await _userManager.RemoveFromRoleAsync(user, role.RoleName);
}
return RedirectToAction("Index", "User");
}
public IActionResult RoleList()
{
return View(_roleManager.Roles.ToList());
}
public async Task<IActionResult> DeleteRole(string id)
{
IdentityRole role = await _roleManager.FindByIdAsync(id);
IdentityResult result = await _roleManager.DeleteAsync(role);
if (result.Succeeded)
{
//Başarılı...
}
return RedirectToAction("Index");
}
public async Task<IActionResult> CreateRole(string id)
{
if (id != null)
{
IdentityRole role = await _roleManager.FindByIdAsync(id);
return View(new RoleViewModel
{
Name = role.Name
});
}
return View();
}
[HttpPost]
public async Task<IActionResult> CreateRole(RoleViewModel model, string id)
{
IdentityResult result = null;
if (id != null)
{
IdentityRole role = await _roleManager.FindByIdAsync(id);
role.Name = model.Name;
result = await _roleManager.UpdateAsync(role);
}
else
result = await _roleManager.CreateAsync(new IdentityRole { Name = model.Name });
if (result.Succeeded)
{
//Başarılı...
}
return View();
}
//[Authorize]
public IActionResult UserRoleList()
{
return View(_userManager.Users);
}
}
Found something here I am using: https://github.com/dotnet/aspnetcore/issues/8149#issuecomment-471927034
/// <summary>
/// https://github.com/dotnet/aspnetcore/issues/8149#issuecomment-471927034
/// </summary>
public class OverrideFilter : ActionFilterAttribute
{
public Type Type { get; set; }
}
public class OverrideFilterProvider : IFilterProvider
{
public int Order => 1;
public void OnProvidersExecuted(FilterProviderContext context) { }
public void OnProvidersExecuting(FilterProviderContext context)
{
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
{
//Check whether the method has any OverrideFilter
var overrideFilters = context.Results.Where(filterItem => filterItem.Filter is OverrideFilter).ToList();
foreach (var overrideFilter in overrideFilters)
{
//Remove the filters of the corresponding type, but with smaller scope
context.Results.RemoveAll(filterItem =>
filterItem.Descriptor.Filter.GetType() == ((OverrideFilter)overrideFilter.Filter).Type &&
filterItem.Descriptor.Scope < overrideFilter.Descriptor.Scope);
}
}
}
}
public class OverrideAuthorization : OverrideFilter
{
public OverrideAuthorization()
{
Type = typeof(AuthorizeFilter);
}
}
/// <summary>
/// https://stackoverflow.com/questions/16606281/linq-to-remove-certain-elements-from-a-ilistt-based-on-a-ilistint
/// </summary>
public static class IListExt
{
public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
int count = 0;
for (int i = list.Count - 1; i >= 0; i--)
{
if (match(list[i]))
{
++count;
list.RemoveAt(i);
}
}
return count;
}
}
Finally we inject it as follows (I am not sure this is the right wat to inject it, but it works);
services.TryAddEnumerable(ServiceDescriptor.Singleton<IFilterProvider, OverrideFilterProvider>());
Use like
[Authorize(Policy = "ControllerPolicy")
public class MyController : Controller
{
[OverrideAuthorization]
[Authorize(Policy = "ActionPolicy")]
public IActionResult MyAction()
{
//Only ActionPolicy will be applied, while ControllerPolicy will be ignored
}
}

.Net Core get Objects of ApplicationUser

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

How to pass user through login view to safe page in mvc

I have AccountController as
[HttpPost]
public ActionResult Login(string user_name,string password)
{
if (ModelState.IsValid)
{
var x = (from n in db.Customers
where n.User_Name==user_name && n.Password==password
select n).FirstOrDefault();
if (x != null)
{
Session["UserName"] = x.First_Name;
return RedirectToAction("Products","Home");
}
else
{
#ViewBag.ErrorValidationFailed = "Invalid username or password";
return View();
}
}
return View();
}
And HomeController
[Authorize]
public class HomeController : Controller
{
//Some code here
}
Now what should I do, once the verifying the credentials? I want the user to get access to the action methods in the HomeController. But after verifying credentials instead of redirecting to Products action method it says 401 Error. Plz correct me if I am wrong anywhere within
There are two approaches for doing this.
1st Approach:
one way is making a base controller and inherit your controllers from base which need authenticated user:
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["UserName"] == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new JsonResult { Data = "LogOut", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
filterContext.Result = new RedirectResult("~/Account/Login");
}
}
}
and then inherit HomeController from BaseController:
public class HomeController : BaseController
{
}
2nd Approach:
Second Approach is to create a Custom Action Filter Attribute and decorate your actions with it that need authentication:
public class AuthenticateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["UserName"] == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new JsonResult { Data = "LogOut", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
filterContext.Result = RedirectToAction("Login", "Account");
}
}
}
and decorate your action with the attribute which actions should be accessed by authenticated user:
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult AllowAllUserAction()
{
}
[Authenticate]
public ActionResult SomeAction()
{
}
}
Use this code, it should work
[HttpPost]
public ActionResult Login(string user_name,string password)
{
if (ModelState.IsValid)
{
var x = (from n in db.Customers
where n.User_Name==user_name && n.Password==password
select n).FirstOrDefault();
if (x != null)
{
Session["UserName"] = x.First_Name;
//Authenticating the user
FormsAuthentication.SetAuthCookie(x.First_Name, false);
return RedirectToAction("Products","Home");
}
else
{
#ViewBag.ErrorValidationFailed = "Invalid username or password";
return View();
}
}
return View();
}
[HttpPost]
public ActionResult Login(FormCollection formCollection)
{
Credentials credentials = new Credentials();
credentials.Username = formCollection["username"].ToString();
credentials.Password = formCollection["password"].ToString();
var result = ApiHelper.PostLogin<FRP.WebApp.Models.Credentials>(MicroService.Login, "/api/Authenticate/Login", credentials, credentials.Username, credentials.Password);
ViewData["username"] = formCollection["username"];
ViewData["password"] = formCollection["password"];
if (result.Status == Sonata.Framework.Models.BusinessStatus.Ok)
{
ViewData["error"] = "";
return View("About", result);
}
else
{
RegistrationViewModel model = new RegistrationViewModel();
model.Years = ViewHelper.GetYears();
ViewData["error"] = "InValid";
return View("Index",model);
}
}

Categories