I created a basic MVC 4 project. Added the HomeController and Home\Index.cshtml and ContactUs.cshtml.
Add route in Global.asax for ContactUs.
Add a Folder Auth and add a class Auth.css in Auth folder.
using System;
using System.Web;
using System.Web.Http;
using System.Net.Http;
namespace MvcApplicationTestProject1
{
public class AuthAttribute : AuthorizeAttribute
{
//public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
//{
// HandleUnauthorizedRequest(actionContext);
//}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
response.Headers.Add("Location", "http://www.google.com");
actionContext.Response = response;
}
//MVC 4 Web.Http.AuthorizeAttribute has IsAuthorized function but not AuthorizeCore
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
return false;
}
}
}
In HomeController
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
//
// GET: /Home/
[Auth]
public ActionResult ContactUs()
{
return View();
}
}
The problem is when run the code and visit http://localhost:[port number here]/Home/ContactUs,
it does not hit on the override class AuthAttribute.
Does the code have something wrong?
Your comment says you are trying to achieve what is in this post, and yet you copied code not from that post at all, but from a previous SO post: Using custom authorization in MVC 4 that was referring to Web API. And in reading that post you see the difference is in what AuthorizeAttribute you use. You are using System.Web.Http instead of System.Web.Mvc.
If you used the code that you referred to in your comment, then you'd find it would work:
using System.Web;
using System.Web.Mvc;
namespace MvcApplicationTestProject1
{
public class AuthAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return false;
}
}
}
Related
I want to create an attribute based on the authorize attribute that instead of granting a role access to an IActionResult it denies access.
I want to decorate the ActionResult with something like [Deny(Role="role")] so that if the role tries to access this it is redirected back to the refering url.
I have tried to modify the code below but a lot of the methods used do not exist in .netcore 5.0:
public class DenyAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return !base.AuthorizeCore(httpContext);
}
}
Or
public class DenyByControllerActionAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var controller = httpContext.Request.RequestContext.RouteData.GetRequiredString("controller");
var action = httpContext.Request.RequestContext.RouteData.GetRequiredString("action");
var denyRole = string.Format("Deny{0}:{1}", controller, action);
return !httpContext.User.IsInRole(denyRole) && base.AuthorizeCore(httpContext);
}
}
How would go about creating something like the above code examples in .netcore 5.0 since the AuthorizeCore override no longer exist in .net 5.0?
In ASP.NET Core, you need implements Attribute and IAuthorizationFilter to custom authorize attribute:
public class DenyAttribute : Attribute, IAuthorizationFilter
{
public string? Roles { get; set; }
public void OnAuthorization(AuthorizationFilterContext context)
{
var originalUrl = context.HttpContext.Request.Headers["Referer"].ToString();
var userInRole = context.HttpContext.User.IsInRole(Roles);
if(userInRole)
{
context.Result = new RedirectResult(originalUrl);
}
}
}
Controller:
[Deny(Roles = "yourRole")]
public IActionResult Test()
{
return View();
}
I'm trying to run test on the repository Controller 'PeoppleRepositoryController.cs.
I get the below error and I couldn't figure out what exactly it is complaining about.
Can anyone please explain what I need to do to fix this issue?
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
The full stack trace can be seen on the image below:
The controller is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Personkartotek.DAL;
using Personkartotek.Models;
using Personkartotek.Persistence;
namespace Personkartotek.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PeopleRepositoryController : ControllerBase
{
private readonly IUnitOfWork _uoWork;
public PeopleRepositoryController(IUnitOfWork uoWork)
{
_uoWork = uoWork;
}
// GET: api/PeopleRepository
[HttpGet]
public IEnumerable<Person> GetPersons()
{
return _uoWork._People.GetAll();
}
// GET: api/PeopleRepository/5
[HttpGet("{id}")]
public async Task<IActionResult> GetPerson([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var person = _uoWork._People.Get(id);
if (person == null)
{
return NotFound();
}
return Ok(person);
}
//GET: api/PeopleRepository/
[HttpGet("AtAdr/{id}")]
public IActionResult GetPersonsResidingAtAddress([FromRoute] int AddressId)
{
var ResidingPersons = _uoWork._People.GetAllPersonsById(AddressId);
return Ok(ResidingPersons);
}
// PUT: api/PeopleRepository/5
[HttpPut("{id}")]
public async Task<IActionResult> PutPerson([FromRoute] int id, [FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != person.PersonId)
{
return BadRequest();
}
if (!PersonExists(id))
{
return NotFound();
}
_uoWork._People.Put(person);
return NoContent();
}
// POST: api/PeopleRepository
[HttpPost]
public async Task<IActionResult> PostPerson([FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_uoWork._People.Add(person);
_uoWork.Complete();
return CreatedAtAction("GetPerson", new { id = person.PersonId }, person);
}
// DELETE: api/PeopleRepository/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeletePerson([FromRoute] int id)
{
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var person = _uoWork._People.Get(id);
if (person == null) {
return NotFound();
}
_uoWork._People.Remove(person);
_uoWork.Complete();
return Ok(person);
}
private bool PersonExists(int id)
{
return _uoWork.Exist(id);
}
}
}
IUnitOfWork file:
using Personkartotek.DAL.IRepositories;
namespace Personkartotek.DAL
{
public interface IUnitOfWork : IDisposable
{
IPeopleRepository _People { get; }
int Complete();
bool Exist(int id);
}
}
My Startup.cs file set ups:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Personkartotek.DAL;
using Personkartotek.Models.Context;
using Personkartotek.Persistence;
using Swashbuckle.AspNetCore.Swagger;
namespace Personkartotek
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ModelsContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("PersonkartotekDB")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
It complaints because it doesn't know how to create an object of IUnitOfWork which is a dependency on your controller.
So to resolve the issue you need to instruct the framework on what implementation of IUnitOfWork you want to use. Typically you are doing it in your Startup.ConfigureServices method. For exmaple:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUnitOfWork, UnitOfWorkImplementation>();
}
}
Where UnitOfWorkImplementation is a class that implement IUnitOfWork
How to create Custom Authentication Attribute in C# Web API
using System.Web.Http;
using System.Web.Http.Controllers;
namespace WebApiCustomAuthorization
{
public class MyAuthorization : AuthorizeAttribute
{
protected override bool Authorized(HttpActionContext actionContext)
{
return true;
}
}
}
using System.Web.Http;
using System.Web.Http.Controllers;
namespace WebApiCustomAuthorization
{
public class MyAuthorization : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
return actionContext.Request.RequestUri.AbsoluteUri.Contains("m=1") || base.IsAuthorized(actionContext);
}
}
}
Here is the sample code for custom authorize attribute.
public class CustomAuthorize : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() ||
actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
return;
if (!actionContext.RequestContext.Principal.Identity.IsAuthenticated)
throw new HttpResponseException(HttpStatusCode.Unauthorized);
/// additional condition
base.OnAuthorization(actionContext);
}
}
Thanks for looking.
This is a trivial task when using a normal (not WebAPI) action filter as I can just alter the filterContext.Result property like so:
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "controller", "Home" }, {"action", "Index" } });
Unfortunately, I have to use HttpActionContext for WebAPI, so I can not access filterContext.Result.
So what should I do in place of that? I have the filter set up and it does execute at the appropriate time, I just don't know how to make it prevent execution of the requested service endpoint and instead point to a different one.
Here is my controller:
[VerifyToken]
public class ProductController : ApiController
{
#region Public
public List<DAL.Product.CategoryModel> ProductCategories(GenericTokenModel req)
{
return HelperMethods.Cacheable(BLL.Product.GetProductCategories, "AllCategories");
}
public string Error() //This is the endpoint I would like to reach from the filter!
{
return "Not Authorized";
}
#endregion Public
#region Models
public class GenericTokenModel
{
public string Token { get; set; }
}
#endregion Models
}
Here is my filter:
using System.Web.Http.Controllers;
using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;
namespace Web.Filters
{
public class VerifyTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
dynamic test = filterContext.ActionArguments["req"];
if (test.Token != "foo")
{
//How do I redirect from here??
}
base.OnActionExecuting(filterContext);
}
}
}
Any help is appreciated.
The answer in my case was simply to change the Response property of the filterContext rather than to redirect to a different endpoint. This achieved the desired result.
Here is the revised filter:
public class VerifyTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
dynamic test = filterContext.ActionArguments["req"];
if (test.Token != "foo")
{
filterContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
base.OnActionExecuting(filterContext);
}
}
In my MVC 4 application with SimpleMembershipProvider. I'm decorating my controller with attribute [Authorize(Roles = "Admin")].
When Roles is false I'm redirecting user to Login page. How can I change it to redirect to Index page?
You can use custom authorize attribute by overriding AuthorizeAttribute as
[CustomAuthAttribute(Roles = "Admin")]
code:
using System;
using System.Web.Http;
using System.Net.Http;
public class CustomAuthAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
/* if authorization condition fails */
if(!condition)
{
HandleUnauthorizedRequest(actionContext);
}
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "/*ActionName*/" },
{ "controller", "/*ControllerName*/" }
});
}
}