I have a WebAPI controller that requires users to be authenticated and I'm using MS Identity 2.0 for authentication. The controller looks somewhat like this:
[Route("MyRoute")]
[Authorize]
[HttpPost]
public HttpResponseMessage Post([FromBody] string value)
{
if (User.Identity.IsAuthenticated == true)
{
....
}
else
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
If I remove one of these options at a time, in both cases, when an unauthorized user calls the controller, it returns a Forbidden response. What's difference between these two options and there one that's better than the other?
With an [Authorize] attribute, the authorization logic can be overridden with filters and will be located at a central location in code.
The
if (User.Identity.IsAuthenticated == true)
{
....
}
else
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
basically is the same as the default [Authorize] functionality, but you'll be repeating yourself over and over.
A technical detail though, the authorization filters [Authorize] are higher up in the pipeline, so a Forbidden there will be more efficient for your server.
see: http://www.dotnet-tricks.com/Tutorial/mvc/LYHK270114-Detailed-ASP.NET-MVC-Pipeline.html
By "Authorize" attribute you can centrally create your request filter for all your request. its easy to manage. like if want to use different authentication provider like WebSecurity then you just need to change in one class instead of all your web apis like following :
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
////check authentication and return if not authorized
if (actionContext != null)
{
if (!WebSecurity.IsAuthenticated)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { RequestMessage = actionContext.ControllerContext.Request };
return;
}
}
}
}
Related
I have an existing ASP.NET core application where I need to block a set group of users from actions on some of my controllers. I can do this on a per task basic but am looking for a way to function the entire block to avoid as much duplication as possible.
An example of how I did this for a Task is:
public async Task<IActionResult> Index()
{
if(RestrictedUserCheckConditions) return RedirectToAction(nameof("RestrictionView"), "UserErrors");
//continue with action for unrestricted users.
...
}
Is there a way I can function this to achive something like below to avoid too much duplication? Otherwise I have a lot of code to add to a lot of Tasks!
public async Task<IActionResult> Index()
{
RestrictedUserCheck();
//continue with action for unrestricted users.
...
}
Thanks in advance
You can create a Custom Authorize attribute to prevent user access the action method:
For example: create a CustomAuthorizeAttribute with the following code:
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
//this method will access the block users, and transfer the data to the ClaimRequirementFilter
public CustomAuthorizeAttribute(string blockUser) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] { new Claim(ClaimTypes.Name, blockUser) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
readonly Claim _claim; //we can get the block users from this property.
public ClaimRequirementFilter(Claim claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//query current user's claims and check whether current user is in the block user list
var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && _claim.Value.ToLower().Split(',').Contains(c.Value.ToLower()));
//if current user is the block user, prevent user access the action method, and return a forbidresult.
if (hasClaim)
{
context.Result = new ForbidResult();
}
}
}
Then apply the above attribute on the action method:
[CustomAuthorize("bb#hotmail.com,cc#hotmail.com")]
public IActionResult Privacy()
{
return View();
}
the result as below:
[Note] In the above sample, we are using the Asp.net core Identity, after login, it already adds the current user claims. If you don't use Asp.net core Identity, you have to add the claims to the HttpContext by yourself.
Besides, you can also use Policy based and Role based authorization to do it, refer the following links:
Policy-based authorization in ASP.NET Core
Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler
I have an existing API that has No Authentication. It`s a public Web API which several clients use by making simple requests.
Now, there is the need to authorize access to a certain method.
Is there any way to do this, keeping the rest of the controllers and respective methods "open" for the clients that already use this Web API?
How can i identify if the request has permissions to access this "protected" method?
What you'll need to do is add an [Authorize] attribute to the methods you want to protect optionally using the overload that accepts one or more role names that the calling user must be in.
Then what you'll have to implement is a way to ensure that authentication data of the caller is transformed into a Principal object. Setting the Principal is generally something you don't do yourself, but instead have the framework do for you.
If you do want to provide your own interface, you can using an authentication filter implementing the System.Web.Http.Filters.IAuthenticationFilter interface.
So what you'll get is this:
[MyAuthentication]
[Authorize]
public SomeClass MyProtectedMethod() {
return new SomeClass();
}
And then implement the MyAuthentication attribute. Below is an example, the important thing is that you use the context of the incoming request and end up setting the context.Principal property with a new Principal
public class MyAuthentication : ActionFilterAttribute, System.Web.Http.Filters.IAuthenticationFilter {
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
// 1. Look for credentials in the request.
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
// 2. If there are no credentials, do nothing.
if (authorization == null)
{
return;
}
// 3. If there are credentials but the filter does not recognize the
// authentication scheme, do nothing.
if (authorization.Scheme != "Basic")
{
return;
}
// 4. If there are credentials that the filter understands, try to validate them.
// 5. If the credentials are bad, set the error result.
if (String.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
return;
}
Tuple<string, string> userNameAndPasword = ExtractUserNameAndPassword(authorization.Parameter);
if (userNameAndPasword == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
}
string userName = userNameAndPasword.Item1;
string password = userNameAndPasword.Item2;
IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);
if (principal == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
}
// 6. If the credentials are valid, set principal.
else
{
context.Principal = principal;
}
}
... other interface methods here
}
I hope this helps you get on the right track. For more information check this post:
http://www.asp.net/web-api/overview/security/authentication-filters
You can use [Authorize] attribute at particular API method as well as at controller level. In case you put the [Authorize] attribute at controller level then you can use [AllowAnonymous] attribute for those API method which you want to access without authentication.
By default, authorization is globally disabled on application. You can force your controller to only allow authorized requests by adding the action filter [Authorize].
[Authorize] // This will enforce all methods inside should be authorized
public class AuthorizeController : ApiController
{
//this method will only be called if user is authorized
public IHttpActionResult GetList()
{
return Ok();
}
}
You can also force only certain methods be authorized:
public class AuthorizeController : ApiController
{
[Authorize] //this method will only be called if user is authorized
public IHttpActionResult GetList()
{
return Ok();
}
// This method can still be called even if user is not authorized
public IHttpActionResult GetListUnauthorized()
{
return Ok();
}
}
Or just disable authorization on some methods inside a controller that requires authorization:
[Authorize]
public class AuthorizeController : ApiController
{
//this method will only be called if user is authorized
public IHttpActionResult GetList()
{
return Ok();
}
[AllowAnonymous]// This method can be called even if user is not authorized due the AllowAnonymous attribute
public IHttpActionResult GetListUnauthorized()
{
return Ok();
}
}
You can also set who's allowed to access your method by using:
[Authorize(Users="Joey,Billy")]
Or by Rules using:
[Authorize(Roles="Administrator,Manager")]
Or even build a more complex Authorize attribute like in this answer (Based on Claims): Authorization Attribute by Claims
We solved it using [AllowAnonymous] on the method, who we didn't want to be Authenticated but Authorizated, overriding the Authorization.
The Execution flow will goes to method level then its goes to Controller Level. So if you mention as "AllowAnonymous" will execute with out Authorization check.
I have a controller that I only want authenticated users to be able to access. Do I have to put a check in each method in my controller to verify a user is authenticated, or is there another way to handle this? Can I use annotations to do this instead?
Example from my controller:
public ActionResult Index()
{
if (UserVerified())
{
...
}
return RedirectToAction("Login", "Account");
}
public ActionResult FacebookLogin()
{
if (UserVerified())
{
....
}
return RedirectToAction("Login", "Account");
}
private bool UserVerified()
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
return true;
}
return false;
}
You can use AuthorizeAttribute for it.
Put it to every action.
[Authorize]
public ActionResult Index()
{
}
[Authorize]
public ActionResult FacebookLogin()
{
}
It will do the whole work for you. It checks whether the currect user is authenticated. If he is authenticated - proceeds to the action, if he is not - returns to the home page.
You can also add this attribute to a controller. Then all actions will require authorization.
[Authorize]
public class HomeController
{
public ActionResult Index()
{
}
public ActionResult FacebookLogin()
{
}
}
Update: And, yes, as Kamil said. Read this article, please.
http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
You spend some time now and will spend much less time having questions about ASP.NET authentication in future.
By the way, you don't need to check for
User != null && User.Identity != null
If you are using default authentication then you can be always sure that User.Identity is a proper object. You can access User.Identity.IsAuthenticated directly.
Using Authorize attribute is way to go (already answered here). In addition, if you may want to implement some other business rules or filtering checks, you can create a filter class inheriting from AuthorizeAttribute.
e.g.
public class CustomAuthorizeFilter: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false; //User not Authorized
}
else
{
//Check your conditions here
}
}
}
Then decorate your controller or Action as:
[CustomAuthorizeFilter]
public class SomeController
{
}
You can either user [Authorize] attribute which is inbuilt. Or you can develop your custom attribute for the same purpose.
You can start from here for your own attribute:
Create custom attribute
If you want to perform validation on each action method, then put that attribute on Controller level rather than each action method.
You can use [Authorize] attribute above controller methods.
Please follow this link
If you want the authentication rules to apply to all controller actions you can do this:
[someAuthAttribute]
public class HomeController : Controller
{
// pseudo
public ActionResult Index() {
return response;
}
public ActionResult FacebookLogin(){
return response;
}
}
Where Index() and FacebookLogin() will adhere to the authentication rules of [someAuthAttribute]. You can also use this "hierarchy" to apply more specific rules to your action methods. Like this:
[someAuthAttribute]
public class HomeController : Controller
{
// pseudo
public ActionResult Index() {
return response;
}
[someFBAuthAttribute]
public ActionResult FacebookLogin(){
return response;
}
}
You can inherit authorization from a base controller.
[Authorize(Roles = #"Domain\Group")]
public class BaseController : Controller
public class ChildController : BaseController
I would like to make use of AllowAnonymous and a custom AuthenticationFilter. Can someone point me in the right direction to make use of AllowAnonymous or another alternative? Thanks
I've created my own custom filter that inherits from System.Attribute and implements System.Web.Http.Filters.IAuthenticationFilter
public class MyCustomAuthenticationAttribute : Attribute, IAuthenticationFilter
I have been able to successfully add the logic for the AuthenticateAsync method
public async Task AuthenticateAsync(
HttpAuthenticationContext context,
CancellationToken cancellationToken) {}
My problem is that I need to ignore some of my Web API controller actions or controllers. I thought that I could use System.Web.Http.AllowAnonymousAttribute to do this. For example here is a really simple example showing intent.
[MyCustomAuthentication]
public class HomeController : ApiController
{
// no authentication needed allow anonymous
[HttpGet]
[Route("hianonymous")]
[AllowAnonymous]
public IHttpActionResult Hello(string name) {
return Ok(new { message = "hello " + name });
}
// needs to be authenticated
[HttpGet]
[Route("hiauthenticated")]
public IHttpActionResult Hello() {
var name = User.Identity.Name;
return Ok(new { message = "hello authenticated user " + name });
}
}
The problem is that Authenticate() is still called on MyCustomAuthenticationAttribute. I would like to use AllowAnonymous or some other method to accomplish this. Thanks for any input.
I know that I can use my custom authentication attribute at the action level and not controller level but there are cases I would like an entire controller or even as a global filter so I need to be able to excluded on an individual action or controller basis.
Your implementation of IAuthenticationFilter should do NOTHING if it does not find an Authorization scheme it does not recognize.
http://www.asp.net/web-api/overview/security/authentication-filters
// 2. If there are no credentials, do nothing.
if (authorization == null)
{
return;
}
// 3. If there are credentials but the filter does not recognize the
// authentication scheme, do nothing.
if (authorization.Scheme != "Basic")
{
return;
}
The idea is that your filter is simply a way to AUTHENTICATE using a known scheme.
You will still need to use the built in AuthorizeAttribute and AllowAnonymousAttribute to control AUTHORIZATION.
I've came across a controller method marked with System.Web.Http.OverrideAuthenticationAttribute in my current Web API project and I'm curious what this is for?
Searching in Google and Stackoverflow doesn't answer the question. MSDN documentation doesn't contain much information. It only says the following:
Represents a filter attribute that overrides authentication filters
defined at a higher level.
Also, I've taken a look into the sources:
public sealed class OverrideAuthenticationAttribute : Attribute, IOverrideFilter, IFilter
{
public bool AllowMultiple
{
get
{
return false;
}
}
public Type FiltersToOverride
{
get
{
return typeof(IAuthenticationFilter);
}
}
}
But this doesn't shed much light.
So could anybody explain what is the purpose of using the OverrideAuthenticationAttribute? And please give some use cases of it for better understanding.
The OverrideAuthentication attribute is used to suppress global authentication filters, which means that all global Authentication filters (implementing IAuthenticationFilter) will be disabled when using this filter.
Let's say you have a global authentication filter called BasicAuth:
public class BasicAuthAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{ }
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
And the filter is configured as a Global filter for all controllers with this code:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new BasicAuthAttribute());
}
}
Let's say you want to use a different authentication strategy on a single controller or controller action. In that case you could disable the global auth. filters using the OverrideAuthentication attribute, and then configure a new filter you want to use for that specific action. This is helpful when you are integrating with external login providers, and you don't want any existing Global auth filters to mess up your external login authentication.
In the code below the global authentication filters are disabled, and then the HostAuthentication filter is enabled for a single action to enable external login providers (e.g. Facebook):
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(Startup.ExternalCookieAuthenticationType)]
[AllowAnonymous]
[HttpGet("ExternalLogin", RouteName = "ExternalLogin")]
public async Task<IHttpActionResult> ExternalLogin(string provider)
{
// Auth code
}
OverrideAuthentication is for overriding the authentication filters configured at higher levels. Say, you have an authentication filter applied globally like this.
// Applied globally in WebApiConfig
config.Filters.Add(new MyAuthenticationFilter());
And, you want to stop this filter from running for a specific action method or a controller. You can use OverrideAuthentication at that level, like this.
public class ValuesController : ApiController
{
[OverrideAuthentication]
public string Get()
{ ... }
}
Now, in the above example, you have MyAuthenticationFilter applied globally. Say, you want to override that and run another filter, say MyAnotherAuthenticationFilter only for the Post action method. You can do something like this.
public class ValuesController : ApiController
{
// Removes all filters applied globally or at the controller level
[OverrideAuthentication]
[MyAnotherAuthentication] // Puts back only MyAnotherAuthenticationFilter
public string Post(...)
{ ... }
}
More info here. Check out the "Filter Overrides" section.