Is it possible with MVC to allow the whole controller to be accessed by 1 role except one or few methods be accessed by another role?
Where all methods belong to the staff except for Method3 can be access by both clients and staff. Something like below:
[Authorize(Roles = "staff")]
public class StaffController : Controller
{
public StaffController()
{
}
public ActionResult Method1()
{
}
public ActionResult Method2()
{
}
[Authorize(Roles = "staff, customer")]
public ActionResult Method3()
{
}
}
Or another scenario where all belong to the staff except for Method3 where it is exclusively accessible by clients, like below:
[Authorize(Roles = "staff")]
public class StaffController : Controller
{
public StaffController()
{
}
public ActionResult Method1()
{
}
public ActionResult Method2()
{
}
[Authorize(Roles = "customer")]
public ActionResult Method3()
{
}
}
However, the above don't work. In both cases, clients still don't have access to Method3.
Greatly appreciate any help!
I suspect it checks for controller authorisation first, so never gets a chance to check the specific actions for their authorisation.
One solution is to authorise both roles, at the class level, and restrict access on specific methods to just staff.
e.g.
[Authorize(Roles="staff,customer")]
public class StaffController : Controller
{
[Authorize(Roles="staff")]
public StaffController()
{
}
[Authorize(Roles="staff")]
public ActionResult Method1()
{
}
[Authorize(Roles="staff")]
public ActionResult Method2()
{
}
public ActionResult Method3()
{
}
}
Another option is to Restrict (i.e. the opposite of Authorize) using something like the custom attribute on this answer ASP.NET MVC: Opposite of [Authorise]
but as they mention this goes against the "refuse by default" principal of MVC security.
Related
I create a Web Api in asp.net core this the content of Api:
[Route("api/[controller]")]
public class BlogController : Controller
{
public IContext _context { get; set; }
public BlogController(IContext ctx)
{
_context = ctx;
}
[HttpGet]
[Route("api/Blog/GetAllBlog")]
public List<Blog> GetAllBlog()
{
return _context.Blogs.ToList();
}
}
as i know in ASp.net Core (WebApi Template) we don't need any configuration like registration Route, which we need in Asp.net Mvc 5.3 and older.
So when i try to call the GetAllBlog by browser or Postman, by this url http://localhost:14742/api/Blog/GetAllBlog , it gets me 404 error, what is problem?
You have already included the api/[controller] route at the top of the controller class so you don't need to include it again while defining route for accessing method.
In essence, change the Route to api/Blog/GetAllBlog to GetAllBlog. Your code should look like this:
[Route("api/[controller]")]
public class BlogController : Controller
{
public IContext _context { get; set; }
public BlogController(IContext ctx)
{
_context = ctx;
}
[HttpGet]
[Route("GetAllBlog")]
public List<Blog> GetAllBlog()
{
return _context.Blogs.ToList();
}
[HttpGet]
[Route("GetOldBlogs")]
public List<Blog> GetOldBlogs()
{
return _context.Blogs.Where(x => x.CreationDate <= DateTime.Now.AddYears(-2)).ToList();
}
}
You also need to have different route names for methods.
Hope this helps.
just see the scenario
public class CustomerController : ApiController
{
public IEnumerable<Customer> GetCustomersByID(int id)
{
}
public IEnumerable<Customer> GetCustomersByName(string name)
{
}
public IEnumerable<Customer> GetCustomersByEmail(string strEmail)
{
}
}
now tell me what i need to do as a result end user can call three get action by their name. how to handle this situation. thanks
You can set route for each method. Such as:
[Route("GetById/{id}")]
public IEnumerable<Customer> GetCustomersByID(int id)
{
}
You can call it getbyid/3. More details web api routing
Also there is a question for this issue.
I'm currently trying to implement a simple WebAPI 2.0 controller to get and retrieve users from a central table.
Looking at implementing :
GetUserByName(string userName)
GetUserByID(int userId)
GetUserByEmail(string email)
Using Routing I have been able to get the api to work with GetById and GetByName. I have also added a route prefix to the controller level
The code looks like this so far, There isn't very much being done in the API controller at the moment I just wish to test that the correct methods are being hit.
[RoutePrefix("api/user")]
public class UserController : ApiController
{
[Route("")]
[HttpGet]
public IEnumerable<User> Get()
{
return new List<User>();
}
// GET: api/Users/5
[Route("{id:int}")]
public User Get(int id)
{
return new User();
}
[Route("{id}/PasswordHash")]
[HttpGet]
public string PasswordHash(int id)
{
return "test";
}
[Route(Name = "/{userName:alpha}")]
public User GetByName(string userName)
{
return new User();
}
[Route(Name = "/GetByEmail/{email}")]
[HttpGet]
public User GetByEmail(string email)
{
return new User()
}
// POST api/<controller>
[HttpPost]
[Route("")]
public string Post([FromBody]User value)
{
return "test";
}
}
Once I add in the get by email it doesn't seem to work, I've tried giving the method it's own custom routing but unfortunately it doesn't seem to work. Any suggestions would be great.
You have set the name of the routes not the routes themselves, and since both methods have the same signature with one string variable you get the problem, so change your code to be :
[Route("/{userName:alpha}")]
public User GetByName(string userName)
{
return new User();
}
[Route("/GetByEmail/{email}")]
[HttpGet]
public User GetByEmail(string email)
{
return new User()
}
hope this helps.
I created a ASP.net Web API controller like that:
public class UsersController : ApiController
{
//...
public void Put([FromBody]User_API user, long UpdateTicks)
{
user.UpdateTicks = UpdateTicks;
//...
}
}
The "user" parameter will be null if the client does not provide correct arguments. Can I make a global filter to check every parameter like this, and will return a 400 message if any error occurs.
Finally, I got the solution:
public class ModelValidateFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.Any(v => v.Value==null))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
And...
//In Application_Start()
GlobalConfiguration.Configuration.Filters.Add(new ModelValidateFilterAttribute());
I'm using MVC3 and currently i'm following a practice such that I declare one instance of DB Container for every controller. I use that container instance for every request coming to that controller. If I need to go to my models for a query or sth, I send that instance as a parameter to the model's function. So for the whole application, I create and use 4-5 different instances of DB Container class. My question is, does this have a good or bad effect on my database operations? Does it matter to create a seperate container instance? What is the proper way to use container classes?
I believe the mentioned class was called DBContext before.
I am not sure it is what you mean but I can give you an example of an approach I'm following rather often:
Create a sort of 'domainservice class' for the DBContext
public class MyDomainService : IDisposable
{
private MyDbEntities dbo;
private bool isDisposed;
public MyDomainService()
{
dbo = new MyDbEntities();
}
public User GetUser(string userName)
{
return (from usr in dbo.Users
where usr.UserName == userName
select usr).SingleOrDefault();
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
dbo.Dispose();
}
}
Create a custom Controller class that extends Controller or AsyncController
and override the Initialize and Dispose methods:
public class MyController : Controller
{
protected MyDomainService DomainService { get; private set; }
protected override void Initialize(System.Web.Routing.RequestContext
requestContext)
{
base.Initialize(requestContext);
DomainService = new MyDomainService();
}
protected override void Dispose(bool disposing)
{
DomainService.Dispose();
base.Dispose(disposing);
}
}
Now you can use the following approach in per example the HomeController inheriting MyController
public class HomeController : MyController
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string username)
{
var user = DomainService.GetUser(username);
if (user != null)
return RedirectToAction("Account", "Information");
return View();
}
}
This will keep your controllers rather clean.