WebSecurity.CurrentUserId = -1 - c#

Im developing an android app that should login/register and read some data from database.
I have WebApi login controller.
and this is my problem
[HttpPost]
public HttpResponseMessage Post(Login model)
{
if (WebSecurity.Login(model.UserName, model.Password))
{
int userid = WebSecurity.CurrentUserId;// <- this value is = -1
string name = WebSecurity.CurrentUserName;// <- this value is = ""
some query where i need the user id(userid);
}
else
...
}
Why after successful login i still have -1 as a value?
I've noticed that even in the mvc project the same thing happens, but after the successful login the user is redirected to another page where the data is listed (when that controller is executed the current user id is already updated).

WebSecurity.Login sets a cookie. That cookie must be re-read by the framework before the user is authenticated, which means that another web request must occur.
In other words, you must redirect to another page, or another web request must come in before the request will be authenticated.

Related

Prevent login with one user in different browser .NET Core

I want to create a login page that contain user and password with ASP.NET Core 5.
How can I prevent login with one user in different browser?
I would suggest at login you create a unique token that is stored on the server and passed back to the client as either an encrypted cookie value or if you are using Claims authentication as a claim. You then write a filter to test that the sent token matches the server side stored value on Authentication. You may want to store and update a datetime on the token - similar to a sliding cache item - so that you can expire the token.
When another browser or login occurs and the token is within a certain date then you can either suppress the login attempt or generate a new token which would logout the first browser user.
An example filter is shown below.
public class SignOnCheckerFilter : IAuthorizationFilter
{
public SignOnCheckerFilter (){}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool checkOk = false;
if (context.HttpContext.User.Identity.IsAuthenticated)
{
//read cookie or claims
//check match
//if match success
checkOk = true;
}
//return if checkOk
if(checkOk) return;
//return forbidden result if invalid match (you could redirect the user to a logout page?)
context.Result = new ForbidResult();
}
}

Writing Cookie on successful submit in Blazor Application

I have a login page that allows the user to login. In the HandlieValidSubmit() event I check if username and password matches with the value stored in database.
If everything is fine I want to store some data into the usercookie before redirecting to another site. This is the html/blazor-Code:
<EditForm>
<!-- standard form-controls here -->
</EditForm>
#code {
private Models.LoginUser _loginUser = new Models.LoginUser();
private EditContext _editContext;
private void HandleValidSubmit()
{
if (UserApi.Login(_loginUser.Mail, _loginUser.Password, out string error, out Guid? guid))
{
NaviationManager.NavigateTo($"/manage/{guid}");
}
}
}
the Cookie is set from within the Login-Function and looks like this:
public DateTime SetCookie<T>(T data, TimeSpan expiration, bool httpOnly = true, bool secure = true)
{
DateTime expireDate = DateTime.Now.Add(expiration);
if (data == null) return DateTime.Now;
Type dataType = typeof(T);
var response = _httpContextAccessor.HttpContext.Response;
CookieOptions cookieOptions = new CookieOptions
{
HttpOnly = httpOnly,
Secure = secure,
Expires = expireDate
};
foreach (var property in dataType.GetProperties())
{
var storeInCookieAttribute = property.GetCustomAttribute<StoreInCookieAttribute>();
if (storeInCookieAttribute == null) continue;
response.Cookies.Append(BuildCookieKey(dataType.Name, property.Name), property.GetValue(data) as string, cookieOptions);
}
return expireDate;
}
IMHO this is the standard "how-to-write-cookies-in-netcore" - way.
When I try to write the cookie I receive the error:
"The response headers cannot be modified because the response has already started."
I understand what this error wants to tell me. Alas I do not really know how to prevent this. I expected that at this point the response should not have started at all.
Is there another event than HandleValidSubmit() I need to use instead? Or can I just clear the Response before writing the cookie without bad side effects?
Blazor Server App is websocket-based application, not HTTP-based one, so the HttpContext service is not available.
When you create a Blazor Server App with support for IdentityUI, you get in the default template a component ( AuthorizeView ) that enables login and logout. When you click on the "Login" button, you are being redirected to a Login page where you can enter your credentials. The Login page is actually a Razor Page, not part of the Blazor App, meaning that you are no longer in the realm of Blazor, and here in this new realm (The Razor Page), the HttpContext is available, you don't even have to use the HttpContextAccessor, as the HttpContext is provided as a property in the PageModel object. After the user has been logged in, cookies created, etc., he is redirected to Blazor.
This is how you can do it. Just emulate this procedure... Create a Razor Page, where you can do all that stuff. You may also pass a return url, so that you'll be redirected to a specific Component page instead of the the Index Component Page.
Note: HandleValidSubmit() is a method that is called if your forms component elements have passed validation. It has got nothing to do with the issue in question.
Note: To use the NavigationManger.NavigateTo method to navigate to external location (outside of the Blazor App realm), add a second boolean parameter with the value true.
Note: This may help you how to cope . There are also many answers related to the current subject and authentication with OpenID Connect, Okta, IdentityUI, etc. Just look for them if you are in need.
Note: Are you aware that you can store data in the local storage and session storage ?
Hope this helps...

websecurity.login returns true but not actually logged in [duplicate]

I can't understand exactly how simple membership worked. After all configuration I put this code to AccountController to see how it works and is it work at all
string UserName1 = WebSecurity.CurrentUserName;
bool LoginResult= WebSecurity.Login("admin", "111111");
string UserName2 = WebSecurity.CurrentUserName;
WebSecurity.Logout();
And when I run debugger I see that after all finished
UserName1 = ""
LoginResult = true
UserName2 = ""
Everything is ok except UserName2. Why it is empty? The login was successful...
Also I can't see UserID at WebSecurity and WebSecurity.IsAuthentificated is false
Why login was successful but WebSecurity do not shows it at all?
Login does not do what you think it does. It does not immediately set the current user, instead it sets a cookie on the users web browser, and on the next page refresh, asp.net will recognize that cookie and give them an authenticated request.
This is not specific to simple membership, that's how all authentication works in asp.net. Once authenticated, the page has to be refreshed for a login to be recognized.

How to pass query string parameter in asp.net?

I am using Access Control service (ACS). I fetched all identity providers (ip) which i set for my application using the following code :
public ActionResult IdentityProviders(string serviceNamespace, string appId)
{
string idpsJsonEndpoint = string.Format(Global.IdentityProviderJsonEndpoint, serviceNamespace, appId);
var client = new WebClient();
var data = client.DownloadData(idpsJsonEndpoint);
return Content(Encoding.UTF8.GetString(data), "application/json");
}
When user click over the signin link the above code called using ajax and get the ips and display them in jquery-ui dialog. And when user click any one of the ips for login the browser redirect to the selected ip login page. After successful login the control return to my control which i set as a returnUrl. Upto this every thing is works fine.
Now what i am trying to do is to pass some values to identity provider (ip) login page and want to get back those values at my returnUrl controller. For this i searched and came to know that there is a query string parameter known as wctx which we can set and get the value at return url. But i dont know how to do this. Can anybody please guid me how can i achieve this?
It is relatively (pretty) easy.
Your URL for listing IdPs looks something like this:
https://[your_namespace].accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=[your_realm]&reply_to=[configured_return_url_for_your_rp]&context=&request_id=&version=1.0&callback=
This is the most complete request for list of Identity Providers. Your may miss some variables (such as context, or reply_to), but what I show is the complete request.
So now you have two options:
inclide your own reply_to parameter. It must be withing the configured realm. So if your realm is https://www.mygreatapp.com/, your default return URL would probably be something like https://www.mygreatapp.com/returnUrl/ (if your controller to handle ACS response is returnUrlController. Now, you can safely change the reply_to to be https://www.mygreatapp.com/returnUrl/?foo=bar, just make sure you URL Encode the query string.
Use the context parameter. It is safer to use and I would suggest using it. Now your URL for fetching list of IdPs will be something like:
https://[your_namespace].accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=[your_realm]&reply_to=[configured_return_url_for_your_rp]&context=[your_custom_string_value_which_you_may_even_encrypt]&request_id=&version=1.0&callback=
Note the now there is context value present in the request for IdP list ([your_custom_string_value_which_you_may_even_encrypt]). In your returnUrl handler controller, you can check for it with code similar (or equal) to the following:
if (ControllerContext.HttpContext.Request.Form["wresult"] != null)
{
// This is a response from the ACS - you can further inspect the message if you will
SignInResponseMessage message =
WSFederationMessage.CreateFromNameValueCollection(
WSFederationMessage.GetBaseUrl(ControllerContext.HttpContext.Request.Url),
ControllerContext.HttpContext.Request.Form)
as SignInResponseMessage;
if (!string.IsNullOrWhiteSpace(message.Context))
{
// do whatever you want with the context value
}
}
You may want to perform any/more additional checks while handling the SignInResponse from ACS.

MVC Handling a CorpId for the site

I'm not sure I'm handling this the right way, but since I'm running into issues, I assume I'm not.
I have to have a corporation id sent in when loading the login screen.
Looks like this:
public ActionResult LogOn(string id)
{
var sb = new StringBuilder();
sb.AppendLine(string.Format("CorpID: {0}", id));
if(ViewBag.CorpID != null)
sb.AppendLine(string.Format("ViewBag.CorpID: {0}", ViewBag.CorpID));
Guid corpIdGuid;
if (!Guid.TryParse(id, out corpIdGuid) && string.IsNullOrEmpty(ViewBag.CorpID))
return null;
// the id passed in will take presidence over the
// viewbag unless it is blank then we use viewbag
// one way or the other viewbag.corpid should not
// be blank
if(!string.IsNullOrEmpty(id))
ViewBag.CorpID = id;
// Session["CorpId"] = id;
//Not a junk guid.. continue.
return View();
}
I need this to establish what company we will be working with during this session.
The problem I am running into, is when the cookie timeout occurs, which is set to 10 minutes, it directs them back to this login and I have no corpid anymore.
I tried the viewbag and it's being reset.
I tried a cookie, but since it expires, the data is no longer there.
I tried a Profile Manager but since they are logged it, that puts me back to nothing.
How do I maintain this CorpId when the user has timed out and put back on the login screen? I need this information for each screen I have also.
Any input would be greatly appreciated!
You need to create a separate cookie that identifies the Corporate ID that doesn't expire with user's session. Session["CorpId"] will expire with the user session and won't work.
var corpCookie = new HttpCookie("CorpID", id);
corpCookie.Expires = DateTime.Now.AddDays(30.0);
HttpContext.Current.Response.Cookies.Set(corpCookie);
Each time the user logs in, you could update the expiry to make it a sliding expiration. To retrieve the cookie value, use the following:
var corpID = HttpContext.Current.Request.Cookies.Get("CorpID").Value;

Categories