I am currently working with an MVC4 and have a secure area to the site. To manage this, I am working with windows authentication. I have implemented this in web forms some time back but this is the first time I have worked with it in respect of MVC.
I am using cookies to store the auth. So when a user authenticates, it gets persisted to cookie. A user could be in a number of different roles. Should this also get persisted to a cookie?
After authentication, how can I check in controllers, filters etc if the user is logged in and if they are a member of a certain role? Does such information need to be loaded in to the users context on each request?
If you're using a Membership Provider then you should be able to do what you want using Action Filter attributes on your controller methods.
[Authorize]
public ActionResult SomeControllerAction()
{
return View();
}
or to test for a particular role:
[Authorize(Roles = "Administrator,Moderator")]
public ActionResult SomeControllerActionRequiringSpecificRoles()
{
return View();
}
Related
I have two seperate projects in one solution. One is the Web Api and the other is MVC. The Web Api project doesn't have an interface. It has the Owin token generating mechanism. The MVC project has the views for user interface and the controllers for making Http Requests and receiving the responses.
On MVC project, I basicly send the username and password to the /token endpoint of the Web Api project using HttpClient. Then the Web Api project checks whether the credentials are matching the DB or not. And if it they are, it generates and returns the Access Token, Token Type, Expiration Date, the Refresh Token and Username values to the MVC project.
My question is, how can I use the token and other information that Web Api project returns to MVC project to start some kind of "session"? By session I mean, I want create a indicator on the MVC project that shows the user is logged in. That indicator should also be accessible on the view layer (to show the logged in username etc.). Also how should I store the Token and Username on MVC project and be able to post them in the requests to the Api project to access the endpoints that requires Authorization?
P.S. I prefer using HttpClient for the request and responses, not ajax nor any JS frameworks.
Thanks in advance.
Create a Modal like below in MVC project :
class SessionValues
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public string UserName { get; set; }
public DateTime ExpiryDate { get; set; }
}
And Covert the Token API response in this modal object and Store this object in Session variable like
SessionValues tokenData=convert response from token endpoint to this entity
Session["TokenData"]=tokenData;
Now whenever u make an API call, Use the token value stored in Session["TokenData"] for authorization. Also, You can add a check on ExpiryDate property of this to check whether the token is expired or not and if required you can fetch the new token again.
In the Session_Start event, it calls an authenticate_authorize class to return an AuthResult object.
public AuthResult
{
public enumAuthResult Result {get;set;}
public string Controller {get;set;}
public string Action {get;set;}
}
If the Result is not enumAuthorized, the controller and action will be returned to the Session_Start. Then if Request.RedirectToRoute() is used to route to the controller's action, the Session_Start will be in an infinite loop. It seems that RedirectToRoute() always restarts the session. Instead, if Request.Redirect() is used then proper controller's action is fired up normally.
What is the right way to call a controller action without using redirect in Session_Start event?
Should I split the authentication and authorization in Application_AuthenticateRequest and Application_AuthorizeRequest events separately?
If the authentication and authorization are done in separate events, how can I pass the AuthResult object to Session_Start event for it to properly redirect or route to the controller?
Response.RedirectToRoute(AuthResult.Controller, AuthResult.Action);
Response.Redirect(string.Format("{0}/{1}",AuthResult.Controller, AuthResult.Action));
What is the right way to call a controller action without using redirect in Session_Start event?
The right way is to use an Authorization Filter, which runs after the action has been selected. Microsoft has included a default implementation, AuthorizeAttribute, which serves most people's needs with users/roles, but can be inherited if you need to make a custom scheme.
AuthorizeAttribute uses the IPrincipal and IUser interfaces, which can be implemented by any custom security scheme and are implemented with ASP.NET membership and ASP.NET identity.
If you attempt to base your security on URLs, it will be nearly impossible to ensure that every route to an action will go through your security scheme. For example, by default the home page can be accessed through /, /Home, or /Home/Index, so if your URL based authorization only accounts for /, the user will be able to circumvent your security and access your home action through /Home or /Home/Index.
I would recommend against creating your own security scheme - to do so requires experience that you don't have based on your question. Instead, you should review the MVC security overview to find the best option for your application and then go through a tutorial that explains how to implement it. Do note that ASP.NET identity supersedes ASP.NET membership.
I have a ASP.NET MVC website.
I don't really manage users, but I do a login to an external API and then I store a "ASPXFORMSAUTH" cookie.
It's a WCF service. In my controller, I call :
MyWcfServiceClient.Login()
In the AfterReceiveReply, I store the response of the service in a variable :
cookie = httpResponse.Headers[HttpResponseHeader.SetCookie];
Then In the controller, I get this cookie and store it using :
Response.Cookies.Add(cookie);
I'm a beginner with ASP.NET MVC, but can I use the [Authorize] attribute to allow the access to the controllers methods only if the request contains this cookie ? And [AllowAnonymous] on the methods before the API login.
EDIT :
So it should work just adding the [Authorize] attribute ?
I'm calling the controller method using ajax, and the value of Request.Headers["Cookie"] is .ASPXAUTH=1D415AF723......
But I get the ajax error callback...
Am I missing something ?
[Authorize] will allow access to authorized users only.
You can either put it at the top of the controller so it applies to all functions on the controller or in front of individual functions. its more powerful than that though as you can allow only specific users or roles. documentation here
The allow [AllowAnonymous] is used when you have added some sort of Authorize to the whole controller but want to allow access for all to a function on the controller. its not required if the controller doesn't have an authorize attribute on it. example here I think the default MVC account in visual studio uses this on the account controller for password rest and login.
I'm not fully sure since I haven't tried it before. But if you set the correct cookies (the default aspx auth cookie) the AuthorizeAttribute should prevent you from reaching the controller if you aren't authorized. Have you tried using the authorize attribute on a controller and logging in using your external API? Because it might just work out of the box.
Another option is to extend the default attribute by making your own. See the following articles for more information about this.
Article from John Galloway
Another question here on SO about extending the Authorize attribute
MSDN Article about the Authorize attribute
Hey all. I have an ASP.NET MVC application that I am going to be deploying to a live server soon. Theoretically, I would like to password protect the application while I'm beta testing without modifying the underlying code base or membership within the application. I will have several people beta testing, so it is compulsory that it is available on the web. A simple scenario:
User navigates to the application under beta
Perhaps an HttpHandler will process the request and redirect them to an interstitial, temporary login page where they have to enter a beta password to access the application
Stackoverflow used a similar technique when they were under beta test. Any ideas?
An edit for clarification. I don't have access to IIS for this particular application because I'm using a managed host.
A couple ideas:
Use windows authentication for the whole application/site in IIS
The idea you mentioned is also a good approach IMO, implementation would probably be flexible in that case.
You could wire up a quick custom AuthorizeAttribute that checks for a custom Auth cookie. Just decorate your controllers with it under beta and delete them when you're ready to go.
Something like this (PS - Did this on the fly without testing):
public class BetaTestAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//if(cookie checks out ok)
//return true;
//else
//httpContext.Response.Redirect("BetaLoginPage");
return base.AuthorizeCore(httpContext);
}
}
Have an action method like so:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult BetaLogin(string username, string password)
{
if(username == "whatever" && password == "whatever")
{
//create custom cookie
return RedirectToAction("Index", "Home");
}
else
return View();
}
When you crate a new ASP.NET MVC project in Visual Studio, you automatically get an AccountController that uses ASP.NET's underlying MembershipProvider to provide a login mechanism.
Even if you don't have it in your final application, you can use it as a temporary solution until you get your real security mechanism up and running.
It requires you to set up a SQL Server database for those ASP.NET services, but depending on how familiar you are with that, you can do it within ten minutes to a couple of hours.
When the public beta is over, you can just discard the AccountController and the database.
I'm with dhulk -- use Windows Authentication on IIS. That route will allow you to avoid putting any authentication code in your application. Simpler is better, and I'd want to avoid doing the work to implement a membership system then to un-implement it.
I would create a simple login View which sets a Session that gets checked on Session_Start() in your Global.asax file... Like so:
protected void Session_Start()
{
if (!Convert.ToBoolean(Session["authenticated"]))
{
// Redirect to the login View
}
}
When you are ready to open up your application for everyone, just remove the View and the three lines of code in your Global.asax file.
Use the good old RoleProvider and create a Beta role and check it via Authorize
Create your own AuthorizeAttribute and check for the IP address or a cookie
.
I'm using OpenId in my ASP.NET MVC application. Works great :) Once i have the user's OpenId Identifier (once they have authenticated and returned to my site), i load up the users data (to get display name, etc).
From here, i also know their roles.
I'm not sure how to assign the role to the current Forms.Identity.
here's my code...
// Load User...
var user = GetUsers().ByOpenIdIdentifier("blahblahblahbl....");
// Here means we have a user AND all the roles, for that user.
// Forms Authenticate and Redirect.
FormsAuthentication.SetAuthCookie(user.DisplayName, true);
return RedirectToAction("Index", "Home");
How can i change this code so the authenticated user also has their roles assigned?
Update
I stumbled across this web post about making a custom Authorize attribute. Notice how they are checking the logged in users role that exists in the session? Also, the roles are an enumeration :) This is pretty funky, if u ask me :) Nice and simple.
Thoughts (compared to a full on blown RoleProvider class?)
You'll need to write your own RoleProvider and hook it up in the web.config file. Your RoleProvider will take the user's name and figure out their role(s). IPrincipal.IsInRole uses the configured RoleProvider to determine role membership.
Have a look at this article
It shows a simple way to integrate openid with membership roles and profile. Hope can help.