I am new to RESTful services using WebApi. I have a front-end web application that uses FormsAuthentication to authenticate users. I am able to use the User.Identity property without any problems in my MVC controller methods.
However, I want to use Angular to make Ajax calls from the browser to the Restful methods in WebApi. The problem occurs with the user principal in these methods - HttpRequestMessage.GetUserIdentity() always returns null. By contrast, Thread.CurrentPrincipal in these methods correctly returns the currently authenticated user identity. My WebApi controller is decorated with the Authorize attribute.
What am I missing that is stopping GetUserIdentity() from working? Here is my controller.
[Authorize]
public class CategoryController : ApiController
{
public IEnumerable<ICategoryJson> Get(HttpRequestMessage request)
{
var user = request.GetUserPrincipal(); // returns null
var user1 = System.Threading.Thread.CurrentPrincipal; // returns authenticated user identity
return null;
}
}
And here is my Ajax call.
$http.get("/api/Category", config).then(function (response) {
Array.prototype.push.apply(service.list, response.data);
service.listLoading = false;
});
MVC controller inherits from a different base class so that's why it works in the MVC controller and not the Web API.
In Web API 2 you can use RequestContext.Principal or as you have used the Thread.CurrentPrincipal within your controller action to get the users Identity.
I don't think this issue is related to the ajax or angular call. you can try calling the same MVC controller action from the angular code and it should still return the user's identity.
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 am currently working with a legacy .NET Framework application that has a webclient (MVC) and a mobile client. I have successfully configured my project to use bearer tokens for my webapi controllers and session cookies for my mvc controller using the following in my WebApiConfig.cs:
////Tells APIs to ignore the Default Cookie Type Authentication
config.SuppressDefaultHostAuthentication();
config.Filters.Add(newHostAuthenticationFilter(OAuthDefaults.AuthenticationType);
However, within my MVC contrtollers I have some methods that return an IActionResult() and some that return a JSonResult. Is it possible to define an attribute/authshcema on a per basis controller method that would allow my JsonResult controller methods to use bearer tokens instead of cookies sessions, despite not being inside a webapi controller?? This would allow me to call these controller methods from my mobile client and save me a lot of time having to refactor these methods into separate controllers.
Example:
//MVC Controller (Not Web API)
public class HomeController : Controller
{
//Should use cookie session
public ActionResult Index()
{
return View();
}
//Should use bearer tokens
[HttpGet]
public JsonResult GetPrograms()
{
var menu = _menuService.GetMenu();
return new JsonResult
{
Data = menu,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
I am using a WebAPI service in my webapplication. In this service is used for all account functions (/api/account/login, /api/account/logout, ...). Within the same webroot I have a website which uses this webAPI service to communicate with the backend system. So from my C# code i'm calling the IsLoggedIn function in my WebAPI which returns true when I'm logged in. This is working great.
[HttpGet]
public bool IsLoggedIn()
{
return (WebSecurity.IsAuthenticated);
}
In my arearegistration i added the following code:
context.Routes.MapHttpRoute("Account", "api/account/{action}/{id}", new { Controller = "Account", id = RouteParameter.Optional });
And the follwing GlobalConfiguration:
GlobalConfiguration.Configuration.Filters.Add(new ExceptionHandlingAttribute());
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
The custom ExceptionHandlingAttribute checks if the thrown exception is of a specific type and returns a custom ReasonPhrase, so nothing special.
When I'm logged in and call the function from javascript (jQuery) or in Fiddler the IsLoggedIn function returns false. What should I add to my jQuery call to make sure the the right user is still found in the WebAPI? This is happening for POST and GET calls.
Please help :)
It will always be false as REST is stateless, each request knows nothing about previous requests.
You could enable Session State by doing something like this
http://www.strathweb.com/2012/11/adding-session-support-to-asp-net-web-api/
A better approach would be to have your Login call return a token which is then passed on subsequent calls to identify the user. Here's an example:
How to use OAuth 2 - OAuth 2 C# example
I have created 2 very simple methods:
[Authorize]
[HttpGet]
public string getUser()
{
return User.Identity.Name;
}
[HttpPost]
public bool SignIn(Credentials cred)
{
var user = userRepository.ValidateUser(cred);
if (user != null)
{
if (user.IsActive)
{
FormsAuthentication.SetAuthCookie(userRepository.GetUserIdByEmail(cred.Email).ToString(), cred.RememberMe);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
user.UserId.ToString(),
DateTime.UtcNow,
DateTime.UtcNow.AddDays(Convert.ToInt32(ConfigurationManager.AppSettings["CookieTimeoutInDays"])),
true,
"MyTicket",
FormsAuthentication.FormsCookiePath);
//Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
//Create the cookie.
HttpCookie mycookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent)
mycookie.Expires = ticket.Expiration;
Response.AddHeader(FormsAuthentication.FormsCookieName, encTicket);
return true;
}
else
return false;
}
else
{
return false;
}
}
I put these functions in an API controller and a normal controller (the only line thats different is HttpContext.Current.Response.AddHeader(FormsAuthentication.FormsCookieName, encTicket); when its in the api controller). When I authenticate with the normal controller and pass the same cookie back to call getUser() it works, but when I do it to the API controller it does not work..I am using mobile devices to call both of these controllers, not a browser. Now I understand API controller usually uses basic authentication by passing in username and password in the headers in each call, but is there anything wrong with doing it from a normal controller? What are the advantages of using the asp.net web API over just a normal controller?
When I authenticate with the normal controller and pass the same cookie back to call getUser() it works, but when I do it to the API controller it does not work
I'm not sure why that's the case. If you're using the normal templates, note that your ApiController will live under an /api route, and note that the action name won't be part of the URL. If your WebApiConfig says:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
and your controller class is named FooController, then your ApiController URLs will be something like:
http://:33504/api/Foo
(for both the GET and the POST).
Using cookies with Web API generally isn't the best approach, but it is possible if you have a particular need for it.
There are a couple of other places you might be getting tripped up:
You're generating a forms auth cookie twice. The SetAuthCookie line is doing it once, and putting it in a cookie header. Then, the Response.AddHeader is doing it again, putting it in a custom header (not a cookie header).
When you say Response.AddHeader(FormsCookieName) I think you meant: Response.SetCookie(myCookie). Your current code is adding a custom header named FormsCookieName; it's not adding a cookie (in the Set-Cookie header) with that cookie name.
With Web API, using HttpContext.Current.Response isn't generally recommended. Instead, consider returning HttpResponseMessage and setting the header properties on that object.
Now I understand API controller usually uses basic authentication by passing in username and password in the headers in each call, but is there anything wrong with doing it from a normal controller?
When you use Web API, you're generally doing REST and cookies don't fit very well with the hypermedia ideas there. If you're not doing hypermedia/REST, then I suppose you could use cookies, though again it generally isn't the best fit.
What are the advantages of using the asp.net web API over just a normal controller?
Web API gives you a self-host story and the ability to do content negotiation and a nice HTTP programming model. MVC was more designed around HTML specifically (not other content types). If you're returning HTML, MVC probably makes sense. If nothing in your app returns HTML, Web API is probably a better fit.
For this one controller, though, I'd do whatever you do in the rest of your app. (I wouldn't pick a different framework for just this one controller.)
I'm having problem with getting ServiceStack [Authentication] attribute to work in ASP.Net MVC4 controller, pages / action methods with the attribute keep redirecting Users to the login page even after the login details are submitted correctly.
I've followed the SocialBootstrapApi example, with the difference being that all the authentication web service calls are made from the controllers:
this.CreateRestClient().Post<RegistrationResponse>("/register", model);
Other things that I've done so far:
Use my own user session implementation subclassing AuthUserSession (not too different from the example, but using my own implementation of User table)
Inherit ServiceStackController on my BaseController, overriding the default login URL
Enable Auth feature in AppHost with my user session implementation
Registration does work, user auth logic works (even though the session does not persist), and I can see the ss-id and ss-pid cookies in the request.
So my complete list of questions:
How do I make the [Authenticate] attribute work (or, what did I do wrong)?
How do I save and reuse the user session in an MVC controller? At the moment this.UserSession is always null.
How do I logout a user? this.CreateRestClient().Get<AuthResponse>("/auth/logout"); does not seem to work.
Update 1:
The session cookies (ss-id and ss-pid) gets created when I attempt to load the secured page (ones with [Authenticate] attribute), before any credentials get submitted. Is this the expected behaviour?
Update 2:
I can see that the session is saved in MemoryCacheClient, however trying to retrieve it in the base controller via this.Cache.Get<CustomUserSession>(SessionKey) returns null (where SessionKey is like: urn:iauthsession:1)
After much fiddling around, apparently the way to hook ServiceStack authentication is to call the AuthService via:
try {
authResponse = AuthService.Authenticate(new Auth{ UserName = model.UserName, Continue = returnUrl, Password = model.Password });
} catch (Exception ex) {
// Cut for brevity...
}
and NOT authResponse = this.CreateRestClient().Post<AuthResponse>("/auth/credentials", model);!
Where AuthService is defined in the base controller as:
public AuthService AuthService
{
get
{
var authService = ServiceStack.WebHost.Endpoints.AppHostBase.Instance.Container.Resolve<AuthService>();
authService.RequestContext = new HttpRequestContext(
System.Web.HttpContext.Current.Request.ToRequest(),
System.Web.HttpContext.Current.Response.ToResponse(),
null);
return authService;
}
}
Everything else (incl. session) works correctly now.
You can find how it could be done in the ServiceStack Use Cases repository. The following example is based on MVC4 but works perfectly for MVC3 either: CustomAuthenticationMvc.