I'm looking at the nerddinner code and in their AuthenticationController, they have the following code:
if (String.IsNullOrEmpty(alias)) throw new ArgumentException("Value cannot be null or empty.", "alias");
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
userdId.ToString(), // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(30), //Expiration
createPersistentCookie, //Persistent
alias); //since Classic logins don't have a "Friendly Name"
string encTicket = FormsAuthentication.Encrypt(authTicket);
this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
My problem is that I want to move this code into a class that does not inherits from the Controller type. The problem with this is the last line of code where it sets the cookie; Response, which is specific to Controller.
How do I set encTicket to a cookie without having access to the controller? Is there a way to use FormsAuthentication class itself to d this?
You could have a method in your separate class which returns the cookie so that the only thing the controller has to do is add the cookie to the response. IMO cookie management (adding/deleting) is the responsibility of the controller:
var cookie = authService.CreateAuthCookie(userId, alias);
Response.AppendCookie(cookie);
This is how to add the encrypted ticket to the browser cookie without using a controller.
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
Expires = authTicket.Expiration,
Path = FormsAuthentication.FormsCookiePath
};
if (HttpContext.Current != null)
{
HttpContext.Current.Response.Cookies.Add(cookie);
}
Related
I have a problem knowing whether a user is authenticated or not when ajax requests are sent from jQuery.
HttpContext.User.Identity is not empty when a user does a regular request from their browser and the aspxauth cookie is set. When a user tries doing a ajax request from jQuery, the aspxauth is not set at all.
My Web.Config
<authentication mode="Forms">
<forms loginUrl="~/" />
</authentication>
Setting the FormsAuthentication Cookie
var cookie = new AuthCookie
{
UserId = user.UserId,
Email = user.Email,
Name = user.Name,
RememberMe = createPersistentCookie,
TimeZone = user.TimeZone,
CompanyId = user.CompanyId,
Roles = new List<string> { user.Role ?? "user" }
};
string userData = JsonConvert.SerializeObject(cookie);
var ticket = new FormsAuthenticationTicket(1, cookie.Email, DateTime.Now,
DateTime.Now.Add(FormsAuthentication.Timeout),
createPersistentCookie, userData);
string encTicket = FormsAuthentication.Encrypt(ticket);
var httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = DateTime.Now.Add(FormsAuthentication.Timeout) };
_httpContext.Response.Cookies.Add(httpCookie);
When I make requests through my broser, the auth cookie appears:
Whenever I make a request through javascript using $.get() or loading javascript scripts / Any other request through javascript, I get:
The odd thing is that on another ASP application I am using WebSecurity and that works perfectly. The auth cookie is always being sent back from client to server. For this ASP MVC 5 application, when I try to use the FormAuthentication, I cannot get the AuthCookie to proceed through all requests.
you are still able to decorate your class/method with [Authorize] and the like. If you're looking to check inside the controller method you have access to the User Property inherited from System.Web.Mvc.Controller or System.Web.Http.ApiController depending on your controller flavor :
//
// Summary:
// Returns the current principal associated with this request.
//
// Returns:
// The current principal associated with this request.
public IPrincipal User { get; set; }
it can be used like so:
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
// user has access - process request
}
Edit:
Here is an example of an [Api]Controller with an ajax[able] method that uses the controller's User property instead of HttpContext's:
public class HelloController : ApiController
{
[HttpGet]
public IHttpActionResult HelloWorld()
{
try
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
return Ok("Hello There " + User.Identity.Name + "!");
}
else
{
return Ok("Hello There Anonymous!");
}
}
catch { throw; }
}
}
I need to set a cookie value before my view called. otherwise I have to refresh the page to get cookie value in the view. The problem here is the value of cookie will get in controller.
[HttpGet]
[Route("Abstract/{meetingCode}")]
[AllowAnonymous]
public ActionResult Index(string meetingCode)
{
var meetingAbstract = new MeetingAbstract();
meetingAbstract.Meeting = _abstractContext.GetMeetingWithMeetingCode(meetingCode);
if (meetingAbstract.Meeting != null)
{
var cookie = new HttpCookie("_culture");
cookie.Value = meetingAbstract.Meeting.language.language_locale_code;//"en-US";
cookie.Expires = DateTime.Now.AddDays(365);
cookie.Path = "/";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
...
Any other way without refresh the page again to set cookie value?
Cookies have some peculiar behaviour, I mean you create them in the Response stream, to be sent to the client, but they are not available in the Request stream until they are sent from the client.
I mean, you cannot access the cookie unless it is being sent from the client.
Anyway, why you need to refresh your page to access the cookie you just created? Is not easier to use the same variable?
[HttpGet]
[Route("Abstract/{meetingCode}")]
[AllowAnonymous]
public ActionResult Index(string meetingCode)
{
var meetingAbstract = new MeetingAbstract();
meetingAbstract.Meeting = _abstractContext.GetMeetingWithMeetingCode(meetingCode);
var cookie;
if (meetingAbstract.Meeting != null)
{
cookie = new HttpCookie("_culture");
cookie.Value = meetingAbstract.Meeting.language.language_locale_code;//"en-US";
cookie.Expires = DateTime.Now.AddDays(365);
cookie.Path = "/";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
} else {
cookie = this.ControllerContext.HttpContext.Request.Cookies["_culture"];
}
...
in my controller AuthController/signin i have this code:
entities.UserAccount user = (new BLL.GestionUserAccount()).authentifier(email, password);
//storing the userId in a cookie
string roles = (new BLL.GestionUserAccount()).GetUserRoles(user.IdUser);
// Initialize FormsAuthentication, for what it's worth
FormsAuthentication.Initialize();
//
FormsAuthentication.SetAuthCookie(user.IdUser.ToString(), false);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
user.IdUser.ToString(), // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
roles, // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Get the stored user-data, in this case, our roles
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
Response.Cookies.Add(cookie);
return RedirectToAction("index", "Home");
in the master page i have a menu ,in that menu there is an item that is meant to be seen only by admin role.
<% if (HttpContext.Current.User.IsInRole("admin")){ %>
<%=Html.ActionLink("Places", "Places", "Places")%>
<%} %>
even with HttpContext.Current.User conatining the right roles,i can't see the item:
globalx asax:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
Instead of using User.IsInRole(), try the static method Roles.IsUserInRole().
I know it sounds silly but from your image I can only see your userData from your ticket.
The only thing I can think if is if the userData is not going into the principal. (Possibly a problem with the last three lines of glabal.asax.cs)
Something is wrong here:
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
You will need a custom Authorize attribute which will parse the user data portion of the authentication ticket and manually create the IPrincipal. Take a look at this post which illustrates the way I would recommend you to do this in ASP.NET MVC. Never use HttpContext.Current in an ASP.NET MVC application. Not even in your views. Use <% if (User.IsInRole("admin")) { %> instead.
One statement is missing.
After this line:
FormsAuthenticationTicket ticket = id.Ticket;
You need to put this line:
ticket = FormsAuthentication.Decrypt(ticket.Name);
In global.asax assign principal on 2 objects like that:
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
I found it here ASP.NET documentation
We use MVC 3. The default user management is not usable for us as our account info is stored in our own data-store and access goes via our own repository classes.
I'm trying to assign a principal add roles to the HttpContext.User and give out an authorization cookie.
Based on a code snipped I found I tried something like this:
if (UserIsOk(name, password))
{
HttpContext.User =
new GenericPrincipal(
new GenericIdentity(name, "Forms"),
new string[] { "Admin" }
);
FormsAuthentication.SetAuthCookie(name, false);
return Redirect(returnUrl);
}
When the next request is done, the user is authenticated, but he is not in the "Admin" role.
What am I missing?
I think you should implement FormsAuthenticationTicket.
More info here : http://msdn.microsoft.com/en-us/library/aa289844(v=vs.71).aspx
In Mvc it is quite similar.
I have a class called UserSession that is injected into LoginController and that I use in LogOn action :
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Index(LoginInput loginInput, string returnUrl)
{
if (ModelState.IsValid)
{
return (ActionResult)_userSession.LogIn(userToLog, loginInput.RememberMe, CheckForLocalUrl(returnUrl), "~/Home");
}
}
Here's my UserSession LogIn implementation (notice I put the "Admin" role hard coded for the example, but you could pass it as argument) :
public object LogIn(User user, bool isPersistent, string returnUrl, string redirectDefault)
{
var authTicket = new FormsAuthenticationTicket(1, user.Username, DateTime.Now, DateTime.Now.AddYears(1), isPersistent, "Admin", FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (authTicket.IsPersistent) authCookie.Expires = authTicket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);
if (!String.IsNullOrEmpty(returnUrl))
return new RedirectResult(HttpContext.Current.Server.UrlDecode(returnUrl));
return new RedirectResult(redirectDefault);
}
Then in the base controller I've overriden OnAuthorization method to get the cookie :
if (filterContext.HttpContext.Current.User != null)
{
if (filterContext.HttpContext.Current.User.Identity.IsAuthenticated)
{
if( filterContext.HttpContext.Current.User.Identity is FormsIdentity )
{
FormsIdentity id = filterContext.HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = id.Ticket;
string roles = ticket.UserData;
filterContext.HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
I hope this helps. Let me know.
You sure, that roles are enabled, and there is such role?
If not, do following:
In Visual Studio:
Project -> ASP.NET Configuration
Then choose Security, enable roles. Create role "Admin".
Then try your approach
Im setting FormsAuthenticationTicket in the Logon method to manually create an authentication cookie. How do I validate that authentication cookie and assign it the Current.User object. Is it done in the Global.asax page?
Logon code:
FormsAuthenticationTicket Authticket = new
FormsAuthenticationTicket(1,
model.UserName,
DateTime.Now,
DateTime.Now.AddYears(1),
true,
"",
FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(Authticket);
HttpCookie Authcookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (Authticket.IsPersistent) Authcookie.Expires = Authticket.Expiration;
Response.Cookies.Add(Authcookie);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
How do i read this cookie and validate the user?
my code so far in the global.asax file:
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id,null);
Context.User = principal;
}
I moved this type of code into a base controller. There is a method called "OnAuthorization" in the Controller class that can be overridden.
It's been a little while, but I believe all requests (images, css... etc) where going through the OnAuthorization method in the Global.asax. By pushing the authorization down to the controller you are only getting the request to your controller/actions