Problem
When I change my controller to inherit from UmbracoAuthorizedApiController instead of UmbracoApiController I will get 401-Unauthorized and I will be redirected to loging page.
Mode Details
I want to call some of my backend Api's from the back-office and to do that I've followed the article in our.umbraco.
First I've implemented a controller inheriting from UmbracoApiController to be able to call my services from postman. Everything went fine and I could call my code and read data from Umbraco:
[RoutePrefix("api/admins")]
public class AdminsController : UmbracoApiController
{
[HttpGet]
[Route("getdata")]
public DataViewModel GetData(string id)
{
....
}
}
Then I've called my service from JavaScript in Dashboard using the plugins
$http.get(vm.baseUrl + '/getdata?id=' + id, {})
.then(function (response) {....}
Everything works fine, I can see that my cookies (containing token) has been sent in the request headers.
Then I've updated my controller to inherit from UmbracoAuthorizedApiController and now I don't have access to my Apis.
The controller is now like this:
[RoutePrefix("api/admins")]
public class AdminsController : UmbracoAuthorizedApiController
What did I do wrong?
Authorized controllers (same as other wrapped MVC controllers in Umbraco) are automatically routed. Backoffice authorisation will work when /umbraco/backoffice/ path will be present in the route.
Check: https://our.umbraco.org/documentation/reference/routing/Authorized/
and: https://our.umbraco.org/documentation/reference/routing/webapi/authorization
It's directly said:
In order for Umbraco to authentication a request for the back office,
the routing needs to be specific. Any URL that routes to :
/umbraco/backoffice/*
will be authenticated. If you have a controller
that is not routed within the prefix, it will not be authenticated for
back office use.
Related
I am bit new in asp.net mvc. so i have a confusion where it is mention in project that unauthorize access redirect user to login page. before jumping to code i like to understand this and that is why i am positing this question where i am not able to post any code example rather i am looking for concept and guide line.
suppose i am developing a site with ASP.Net MVC core. i have created a empty project where i add two controller.
one is Home and login controller.
Home controller's index action is not protected by Authorized attribute but Home controller's product action is protected.
when user try to access product action then user should be redirected to login page if not signed in. so tell me how to setup project in classic mvc or mvc core where i will mention that user should be redirected to login page if user is not signed in.
i will not use identity rather i will check user credentials from db using ado.net.
please guide me step wise that what i need to follow.
Thanks
You can use type filter attributes to achieve that. For example if you have a BaseController class and it gets inherited in all your Controller classes, you can add a filter attribute there so that you can run your filtering's (for example: Redirect unauthorized user) before or after specific stages in the request processing pipeline.
[CheckAccessPublicStore]
public abstract class BaseController : Controller
{
}
If you want to only filter your Action method
[CheckAccessPublicStore]
public virtual IActionResult Product()
{
return new EmptyResult();
}
Then
public class CheckAccessPublicStoreAttribute : TypeFilterAttribute
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.PublicStoreAllowNavigation))
context.Result = = new RedirectToRouteResult(new RouteValueDictionary {
{ "controller", "Customer" },
{ "action", "LogIn" }
});
}
}
For more you can learn here: https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0
I have controller, and it's name is "AuthController" which is being inherited by "BaseController". "AuthController" has a parametric constructor as well a method "RegisterFromOutside" that is being used to register the user. Below code work fine for the Non Api Controller.
Code Sample for Non Api Controller:
Now the question is how can I use the API controller to call the same method? and then access it from my mobile application (using the same implementations). Please note that project doesn't have any implementation for API calling yet.
This is when is am getting this error. and the error is
"But when i tried to access the same UserServices from the other Web API application controller with Parametric constructor. It asks me to declare parameter-less constructor. and when i do that it simply don't run the parametric constructor and in return i receive null reference exception."
public class ValuesController : ApiController
{
UserServices _userServices;
public ValuesController(
UserServices userServices)
{
_userServices = userServices;
}
// POST api/values
public void Post([FromBody]RegisterViewModel model)
{
RegisterFromOutside(model);
}
public void RegisterFromOutside(RegisterViewModel model)
{
User user = _userServices.Register(model.Username, model.Password, model.Email);
}
}
You can add API controller in MVC project(right click on folder Controllers, choose Add
--> Controller)
There is method signature in my project, which executes user authorization, you can do the same thing(you can also try to do that in classic non-API controller)
[AllowAnonymous]
[HttpPost]
[Route("api/mobile/users/login")]
public LoginResponseModel Login(LoginRequestModel loginRequestModel)
I have an Action in a Controller that uses the OutputCache attribute
public class PostsController : Controller
{
[OutputCache(3600, VaryByParam="id")]
public ActionResult Index(Guid id)
{
var post = PostRepository.GetById(id);
return View(post);
}
}
When a frontend user requests posts/{id} the page is cached and works very well. But...
The posts are created on another site (a backend in a different assembly), and sometimes, the backend user wants to fix a typo or change the post in any way. She can do this task with no problem (since the backend is not affected by the cache). But, obviously, the frontend user must waits for the cache to invalidate to read the most recent version. Is there a way to trigger a frontend cache refresh when the user updates the post in the backend?
TL;DR Summary: Can I configure MVC Web API routing for HTTP GET, PUT & DELETE?
I've been looking into replacing our old Data Access Layer (a DLL based on DataSets and TableAdapters) with a private API, with a view to creating a public API if it's successful. I've done some work with MVC 4 to refresh our frontend, and loved working with it, so it seems sensible to explore the "Web API" project type before diving into WS- or WCF-based libraries.
An initial demo allows me to return XML/JSON nicely, for example:
//service.url/api/Users
... returns a list of users, while a specific user's details can be accessed via:
//service.url/api/Users/99
So far, so RESTful. However, in order to truly map URIs to resources I want to do an HTTP PUT (new user) or HTTP DELETE (remove user) to the the URI listed above. In all of the examples I've seen for these projects, along with the Scaffolds provided in Visual Studio, this convention is followed:
//service.url/api/Users/Create
//service.url/api/Users/Delete/99
//service.url/api/Users/Update/99
... and so on. This feels like side-stepping the issue to me, which is a shame when what's there has been put together so nicely!
Any thoughts on how best to approach this?
What you want is the default in MVC Web API. I'm not sure what you are looking at but here is a great example of routing the Get/Post/Put/Delete to actions.
For example you may want:
public class UsersController : ApiController
{
// GET http://service.url/api/Users/1
[HttpGet]
public User GetUser(int id);
// POST http://service.url/api/Users/?name=richard...
[HttpPost]
public User AddUser(User model);
// PUT http://service.url/api/Users/?id=1&name=Richard...
[HttpPut]
public User UpdateUser(User model);
// DELETE http://service.url/api/Users/1
[HttpDelete]
public User DeleteUser(int id);
}
I've explicitly set these, but the GetUser and DeleteUser don't need the prefix because they start with the matching HTTP method.
The link provided by Erik is a good start, but I see how it can confuse the situation when looking for a simple RESTful API that makes use of the HTTP verbs to perform these CRUD actions. If you're looking to use the HTTP verbs of GET, PUT, POST, and DELETE (and possibly PATCH, but I'm not covering that here) and you're ok with using convention, then the following would work:
public class UsersController : ApiController
{
// GET http://service.url/api/Users
public User GetAllUsers(){ ... }
// GET http://service.url/api/Users/1
public User GetUser(int id){ ... }
// POST http://service.url/api/Users/
// User model is passed in body of HTTP Request
public User PostUser([FromBody]User model){ ... }
// PUT http://service.url/api/Users/1
// User model is passed in body of HTTP Request
public User PutUser(int id, [FromBody]User model){ ... }
// DELETE http://service.url/api/Users/1
public User DeleteUser(int id){ ... }
}
Note that the attributes on the method are not needed when using the HTTP verb action convention in Web API. Also, note that I use the [FromBody] attribute on the User parameter for POST and PUT to denote that the body contains the data I wish to send. This may not be most convenient for POST if you're trying to append to a resource, and I have not tried creating/modifying data through query parameters using Web API. It certainly makes the call feel very clean to place your data in the body. "POST/PUT this content in the body at this resource."
Also, the way I read PUT in the spec, and I could very well be wrong, is that it acts as a replace. That also makes sense given the last line above. I'm PUTting this resource in this location, replacing what was already there. The spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) states: "If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server." The term they use is "modified" so I guess that leaves enough room for interpretation for the end user. That's where PATCH comes in (https://www.rfc-editor.org/rfc/rfc5789), but I don't have enough information to comment on that at this time.
I'm using ASP.NET MVC 2 and have a login page that is secured via HTTPS. To ensure that the user always accesses those pages via SSL, I've added the attribute [RequireHttps] to the controller. This does the job perfectly.
When they have successfully logged in, I'd like to redirect them back to HTTP version. However, there isn't a [RequireHttp] attribute and I'm struggling to get my head around how I might achieve this.
The added (potential) complication is that the website when in production is hosted at the route of the domain, but for development and testing purposes it is within a sub directory / virtual directory / application.
Am I over-thinking this and is there an easy solution staring me in the face? Or is it a little more complex?
After a bit of digging, I went along the lines of rolling my own as there didn't appear to be a good built-in solution to this (as mentioned, there is a great one for MVC2 applications in the form of [RequireHttps]). Inspired by çağdaş's solution to this problem and I adapated to come up with the following code:
public class RequireHttp : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// If the request has arrived via HTTPS...
if (filterContext.HttpContext.Request.IsSecureConnection)
{
filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.Url.ToString().Replace("https:", "http:")); // Go on, bugger off "s"!
filterContext.Result.ExecuteResult(filterContext);
}
base.OnActionExecuting(filterContext);
}
}
I can now add this to my Controller methods and it behaves (seemingly) as expected. If I redirect to the Index action on my controller from a HTTPS protocol, it will redirect to HTTP. It only allows HTTP access to the Index ActionResult.
[RequireHttp]
public ActionResult Index() {
return View();
}