I have some miss understanding in authentication using "User.Identity" and "FormsAuthentication.SetAuthCookie".
I have this action:
public ActionResult Login(string userName, string password)
{
if (Membership.ValidateUser(userName, password))
{
FormsAuthentication.SetAuthCookie(userName, true);
var isAuth = User.Identity.IsAuthenticated;
return View("Desktop");
}
return View("Login");
}
My question is why the value of the isAuth variable false after I set authentication ticket using this row(User.Identity.IsAuthenticated)?
By calling FormsAuthentication.SetAuthCookie you're simply dumping the authentication cookie to the HTTP response. At this stage the request is still considered as 'non-authenticated'.
Only the following requests (which will include the authentication cookie) will be considered as 'authenticated' and will have the User property set to the appropriate value.
If you want your HTTP request to immediately have the (just-authenticated) user set. Try this:
var user = new GenericPrincipal(new GenericIdentity(userName), null);
HttpContext.Current.User = Thread.CurrentPrincipal = currentUser;
MVC uses the standard ASP.Net pipeline. One part of the pipeline is authenticating the user. If a user is logged in after the pipeline has authenticated as anonymous, the only way to rerun the process is to redirect the user so the pipeline can authenticate the user. In your scenario, after you set the cookie, you'll need to do a redirect back to whatever action you want the user to go to.
Related
My app creates an Guid Event token
The customer visits the url of the event like so.
https://example.com/event/a3b2e538-e87c-4444-a655-5171f263ac70
The customer is then redirected to a login form to provide the event password.
If the password maches the event token customer will be able to see the event.
Can i acomblish this without an Identity user account? (I do not wish to follow the classical user identity login approach, in this case).
Maybe something like creating an auth cookie and use it, in the upcoming requests.
[HttpPost]
[Route("validate/{code}")]
public IActionResult Cookie(string code)
{
var user = true; //Validate event token against event password supplied by user
if (user == true)
{
var ident = _userManager.CreateAuthCookie(user, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);
return Redirect("Wherever");
}
ModelState.AddModelError("", "Invalid login attempt");
return View();
}
I guess, I understand your point. You want to create a custom Owin Authentication Framework. The same thing can be achieved using JWT token. It has advantages over OWIN Authentication.
But if you want to design something like this using OWIN, Please take care of these:
First and most important thing, the parameter passed in the url should not have any password or sensitive value. The URL token should be encoded (for encoding u can refer https://www.nuget.org/packages/Microsoft.Owin.Security/) and that encoded token can carry this information. While encoding, you can encode someID (not email address), some sourcecd (that tells the token is from the valid source), some time limit and how many times that token will be valid.
Now, when you get the call to your API end point, you can decode that token, validate and then extract that someID, and make a call to your DB to understand, if the user is valid.
Important: Encoding and decoding algorithm plays a very important role here. So, your encoding and decoding token should not be exposed anywhere.
If he is a valid user, then create a claimsIdentity object.
ClaimsIdentity identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identity.FindFirst("sub").Value));
identity.AddClaim(new Claim("Name", <<add your claims like this>>));
identity = new ClaimsIdentity(identity.Claims, "ApplicationCookie");
AuthenticationProperties properties = new AuthenticationProperties();
AuthenticationManager.SignIn(properties, identity);
Setup Authentication class object in your controller or to a seperate file:
using Microsoft.Owin.Security;
private IAuthenticationManager authenticationManager;
public IAuthenticationManager AuthenticationManager
{
get
{
if (authenticationManager == null)
authenticationManager = HttpContext.GetOwinContext().Authentication;
return authenticationManager;
}
set { authenticationManager = value; }
}
You should also have OWIN layer configured in the middlelayer. You can configure OWIN middle layer based on .Net framework or .Net Core
I have this case where I have an anonymous endpoint can work on it's own but if a user have already done authentication with the cookie I need to get from that authenticated cookie session the data about the authenticated user, but as I searched online I haven't found a solution to this and the User.Identity.IsAuthenticated is always false despite the user has the authenticated session cookie but on a Anonymous endpoint it's like being ignored so I can't figure out if the user data in the cookie.
Is there any way to accomplish this?
Example of the needed behaviour:
[HttpGet,AllowAnonymous]
public async Task<IActionResult> GetSomething()
{
if(User.Identity.IsAuthenticated){
//Get data from User.Claims and act upon it
} else {
//Get data without user logic
}
}
You still must use the Authorize attribute. The AllowAnonymous attribute serves to still allow access if the user isn't authorized.
[HttpGet,Authorize,AllowAnonymous]
public async Task<IActionResult> GetSomething()
I managed to implement this token based authentication system in my application, but I have a little question. How can I check if a user is signed it (eg if the there is a valid token in the request) within the method? So with the [Authorize] ?
So I have controller, and in that controller I want to check if the user is signed in. I thought of using this:
if (_signInManager.IsSignedIn(ClaimsPrincipal.Current))
{
...
}
but it does not work since ClaimsPrincipal.Current is always null
You don't need to use the SigninManager or something similar. The user is injected on the pipeline (on the User property of the base controller) and it's info is filled automatically by the authentication middleware (cookie or token). So, on your controller:
bool isAuthenticated = User.Identity.IsAuthenticated;
yes . put [Authorize] attribute above your class or methods to check if user is authenticate or not. You can get user by this code:
var principal = User as ClaimsPrincipal;
var check = User.Identity.IsAuthenticated;
I am following this tutorial yet it does not tell you how to logout. I tried to do
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
Request.GetOwinContext().Authentication.SignOut()
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
You can get the sample code here: https://github.com/AndersAbel/SocialLoginWithoutIdentity
Just need to add one more action
public ActionResult SignOut()
{
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
return RedirectToAction("Index", "Home");
}
This method plus any one of the 3 lines of I posted above
My result right now is, I login, I go to secure page and can see it, I then proceed to my signout and then after signout try to go back to the secure page and I am allowed back to that secure page.
So it actually did not really sign me out.
As mentioned in the tutorial, the middleWare used use the default authentication type but don't override it.
By using only externalCookie as parameter for Owin you are clearing the cookie for Asp, but not the one used to store the Google provider,
to do so, you will have to get the array of all current cookies.
It can be done the easy way like this:
Request.GetOwinContext()
.Authentication
.SignOut(HttpContext.GetOwinContext()
.Authentication.GetAuthenticationTypes()
.Select(o => o.AuthenticationType).ToArray());
This is where it is said on the Tutorial:
The call to UseGoogleAuthentication should be quite obvious why it’s needed.
But the first one toSetDefaultSignInAsAuthenticationType is not as
obvious.
login middleware normally relies on the external cookie middleware
registered before the social login middleware.
external cookie middleware, it sets itself as the default signin type.
That’s how the social login middleware knows that it should use the
external cookie. In this setup there is no external cookie, so we have
to manually set the main cookie middleware as the default signin type.
The cookie middleware will only issue a cookie if the
AuthenticationType matches the one in the identity created by the
social login middleware.Looking at the owin external authentication pipeline a socialIn the setup of the
Try setting the cache control headers.
public ActionResult SignOut() {
var authenticationTypes = new string[] {
DefaultAuthenticationTypes.ApplicationCookie,
DefaultAuthenticationTypes.ExternalCookie
};
AuthenticationManager.SignOut(authenticationTypes);
// HACK: Prevent user from being able to go back to a logged in page once logged out
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
// now redirect
return RedirectToAction("Index", "Home");
}
private IAuthenticationManager AuthenticationManager {
get {
return Request.GetOwinContext().Authentication;
}
}
There is no stopping the user clicking the back button on the browser, unless you try JavaScript, which can be disabled. The user can go back a page and view what was on the previous page, but if they try to click any protected links or refresh the page, they will be redirected to log in.
Use the [Authorize] attribute on classes which need authorization:
[Authorize]
public class MeController : ApiController
{
// GET api/<controller>
public IEnumerable<object> Get()
{
var identity = User.Identity as ClaimsIdentity;
return identity.Claims.Select(c => new
{
Type = c.Type,
Value = c.Value
});
}
}
source: http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
I am working on a single page application using AngularJS and ASP.NET Identity 2. I log the user in and the cookie is set; however, when I check the Identity of the user on the same request, it shows it as blank and IsAuthenticated is false. However, these are populated on subsequent requests. I was hoping to send back to the UI whether or not the user was logged in on the same request. Is this possible?
Code as requested (AngularJS makes AJAX post into WebAPI controller Login method)
[HttpPost]
[AllowAnonymous]
[Route("Login")]
public async Task<IHttpActionResult> Login(LoginModel loginModel)
{
var result = await _securityService.Login(loginModel.UserName, loginModel.Password);
if (!result)
{
ModelState.AddModelError("errorMessage", "Invalid username or password.");
return BadRequest(ModelState);
}
return Ok();
}
public async Task<bool> Login(string userName, string password, bool persistCookie = false)
{
var user = await _userManager.FindAsync(userName, password);
if (user != null)
await SignInAsync(user, persistCookie);
else
return false;
return true;
}
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
_authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
_authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, await CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie));
}
public Task<ClaimsIdentity> CreateIdentity(ApplicationUser user, string authenticationType)
{
return _userManager.CreateIdentityAsync(user, authenticationType);
}
You won't get a signed in identity until the next request because the call to SignIn is what's causing a cookie to be set on the response. That cookie will turn into the identity on subsequent requests, but its too late to change your current request's identity.
When using Owin authentication, the AuthenticationManager.SignIn() method barely sends a message to the cookie handler to set a cookie when the cookie handler gets to handle the request after the Web API Controller (see my blog post Understanding the Owin External Authentication Pipeline for details).
But the Login method returns true if the login was successful and false if not, so you can use that information in the Login action to send back information. If you don't only want to know if the login succeeded or not, but also want the actual identity you can change Login() to return the user in case of successful login and null if failed.
I log the user in and the cookie is set; however, when I check the Identity of the user on the same request, it shows it as blank and IsAuthenticated is false.
This is just a lack of knowledge on your part about how the ASP.Net pipeline works.
There is a fairly large pipeline of events that occur. I'm pretty sure MVC runs in the ProcessRequest method. This method is after the AuthenticateRequest event and the PostAuthenticateRequest event. This means that the entire ASP.Net authentication framework can never be updated during the ProcessRequest method. This is why you'll see almost all system do a redirect afterwards, so that the next request has all the authentication (IIdentity, IPrincipal, IsAuthenticated, etc).
I was hoping to send back to the UI whether or not the user was logged in on the same request. Is this possible?
How could the code not be able to? The first request either authenticates them or not, whatever code is doing that knows if they are authenticated.
I was hoping to send back to the UI whether or not the user was logged in on the same request. Is this possible?
Yes. As said in other responses, you can.
I just want to cover the case when you are in the same request but outside the context where the SignIn took place.
Through Owin, you could use something like this extension method:
/// <summary>
/// Check if the user was authenticated in the current request, or in a previous one
/// </summary>
public static bool IsUserAuthenticated(this IOwinContext context)
{
if (context.Request.User.Identity.IsAuthenticated)
return true;
if (null != context.Authentication.AuthenticationResponseGrant && null != context.Authentication.AuthenticationResponseGrant.Identity)
{
return context.Authentication.AuthenticationResponseGrant.Identity.IsAuthenticated;
}
return false;
}