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);
}
}
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 have created a custom attribute and I am trying to retrieve the value of this custom attribute in asp.net action filter but it seems to be unavailable. What am I doing wrong?
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public sealed class MyCustomAttribute : Attribute
{
MyCustomAttribute(string param)
{
}
}
public class MyCustomActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
public void OnActionExecuting(ActionExecutingContext context)
{
// unable to find my custom attribute here under context.Filters or anywhere else.
}
}
[HttpGet]
[MyCustomAttribute ("test123")]
public async Task<Details> GetDetails(
{
}
What you want to achieve is a little more complicated if you want to do it yourself (ie. reflecting attribute value from method of Controller).
I would recommend using built-in attribute filters from ASP.NET Core (more in ASP.NET Core documentation), in your example:
public class MyCustomActionAttribute : ActionFilterAttribute
{
private readonly string param;
public MyCustomActionAttribute(string param)
{
this.param = param;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var paramValue = param;
base.OnActionExecuting(context);
}
}
and annotating your controller action like this:
[HttpGet]
[MyCustomAction("test123")]
public async Task<Details> GetDetails()
{
}
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*/" }
});
}
}
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;
}
}
}