I'm trying to get username of currely logged in user by ASP.NET Generic Handler (.ashx). But the username is always nothing even though the user is currently logged in.
Here's my Generic Handler class:
Imports System.Web.SessionState
Public Class FileUploadHandler
Implements System.Web.IHttpHandler
Implements IRequiresSessionState
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
'username is always null, i'm not sure why there's nothing eventhough the user is logged in
Dim username = context.Current.User.Identity.Name
If String.IsNullOrEmpty(username) Then
context.Response.StatusCode = 0
Else
context.Response.StatusCode = 1
End If
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
But I can get the username of the logged in user from any page like this:
Dim username = Context.Current.User.Identity.Name
Do you think what it is the problem here?
I'm OK with both C# and VB.NET. Thanks.
If you are using any client side component such as Uploadify, Plupload, it can be that the component is not sending authentication and session cookies with the request. There is a good explanation here for workaround.
Check out Uploadify (Session and authentication) with ASP.NET
The default ASP.NET application built up uses cookie to authenticate users via session-id which is written in the cookie itself, while I think it should be the session object that is to deal with this. Therefore the default created MVC application is not safe to follow. you'd better change the source code into using session instead.
For your issue, getting username from the user class might not be a good option as it will return an empty string. If you use session this problem will be resolved once you use the identity from the session object.
Related
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...
In a forms model, I used to get the current logged-in user by:
Page.CurrentUser
How do I get the current user inside a controller class in ASP.NET MVC?
If you need to get the user from within the controller, use the User property of Controller. If you need it from the view, I would populate what you specifically need in the ViewData, or you could just call User as I think it's a property of ViewPage.
I found that User works, that is, User.Identity.Name or User.IsInRole("Administrator").
Try HttpContext.Current.User.
Public Shared Property Current() As
System.Web.HttpContext
Member of System.Web.HttpContext
Summary:
Gets or sets the System.Web.HttpContext object for the current HTTP request.
Return Values:
The System.Web.HttpContext for the current
HTTP request
You can get the name of the user in ASP.NET MVC4 like this:
System.Web.HttpContext.Current.User.Identity.Name
I realize this is really old, but I'm just getting started with ASP.NET MVC, so I thought I'd stick my two cents in:
Request.IsAuthenticated tells you if the user is authenticated.
Page.User.Identity gives you the identity of the logged-in user.
I use:
Membership.GetUser().UserName
I am not sure this will work in ASP.NET MVC, but it's worth a shot :)
getting logged in username: System.Web.HttpContext.Current.User.Identity.Name
UserName with:
User.Identity.Name
But if you need to get just the ID, you can use:
using Microsoft.AspNet.Identity;
So, you can get directly the User ID:
User.Identity.GetUserId();
In order to reference a user ID created using simple authentication built into ASP.NET MVC 4 in a controller for filtering purposes (which is helpful if you are using database first and Entity Framework 5 to generate code-first bindings and your tables are structured so that a foreign key to the userID is used), you can use
WebSecurity.CurrentUserId
once you add a using statement
using System.Web.Security;
We can use following code to get the current logged in User in ASP.Net MVC:
var user= System.Web.HttpContext.Current.User.Identity.GetUserName();
Also
var userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name; //will give 'Domain//UserName'
Environment.UserName - Will Display format : 'Username'
This page could be what you looking for:
Using Page.User.Identity.Name in MVC3
You just need User.Identity.Name.
Use System.Security.Principal.WindowsIdentity.GetCurrent().Name.
This will get the current logged-in Windows user.
For what it's worth, in ASP.NET MVC 3 you can just use User which returns the user for the current request.
If you are inside your login page, in LoginUser_LoggedIn event for instance, Current.User.Identity.Name will return an empty value, so you have to use yourLoginControlName.UserName property.
MembershipUser u = Membership.GetUser(LoginUser.UserName);
You can use following code:
Request.LogonUserIdentity.Name;
IPrincipal currentUser = HttpContext.Current.User;
bool writeEnable = currentUser.IsInRole("Administrator") ||
...
currentUser.IsInRole("Operator");
var ticket = FormsAuthentication.Decrypt(
HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value);
if (ticket.Expired)
{
throw new InvalidOperationException("Ticket expired.");
}
IPrincipal user = (System.Security.Principal.IPrincipal) new RolePrincipal(new FormsIdentity(ticket));
If you happen to be working in Active Directory on an intranet, here are some tips:
(Windows Server 2012)
Running anything that talks to AD on a web server requires a bunch of changes and patience. Since when running on a web server vs. local IIS/IIS Express it runs in the AppPool's identity so, you have to set it up to impersonate whoever hits the site.
How to get the current logged-in user in an active directory when your ASP.NET MVC application is running on a web server inside the network:
// Find currently logged in user
UserPrincipal adUser = null;
using (HostingEnvironment.Impersonate())
{
var userContext = System.Web.HttpContext.Current.User.Identity;
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, ConfigurationManager.AppSettings["AllowedDomain"], null,
ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);
adUser = UserPrincipal.FindByIdentity(ctx, userContext.Name);
}
//Then work with 'adUser' from here...
You must wrap any calls having to do with 'active directory context' in the following so it's acting as the hosting environment to get the AD information:
using (HostingEnvironment.Impersonate()){ ... }
You must also have impersonate set to true in your web.config:
<system.web>
<identity impersonate="true" />
You must have Windows authentication on in web.config:
<authentication mode="Windows" />
In Asp.net Mvc Identity 2,You can get the current user name by:
var username = System.Web.HttpContext.Current.User.Identity.Name;
In the IIS Manager, under Authentication, disable:
1) Anonymous Authentication
2) Forms Authentication
Then add the following to your controller, to handle testing versus server deployment:
string sUserName = null;
string url = Request.Url.ToString();
if (url.Contains("localhost"))
sUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
else
sUserName = User.Identity.Name;
If any one still reading this then, to access in cshtml file I used in following way.
<li>Hello #User.Identity.Name</li>
We're implementing our own SSO provider using IdentityServer3. We're almost done except that we have the requirement where when the user logs in for the first time they will have to change their username, password and supply other information. The problem lies with the change of the username: it needs to also change the subject id so when the partial login finishes the client also receives the new username, not the old one.
So what we need is a way, in the partial login, to change the sub claim. Searching the internet for this problem didn't give my any useful results. I've tried to change the claim but I'm unable to make it persist beyond the post request. I've done the following:
var ctx = Request.GetOwinContext();
var authentication = await ctx.Authentication.AuthenticateAsync(Constants.PartialSignInAuthenticationType);
authentication.Identity.RemoveClaim(identityResult.Identity.FindFirst("sub"));
authentication.Identity.AddClaim(new Claim("sub", model.NewUsername));
This, unfortunately, doesn't work because the claims I here have are just copies. What is the correct way to change the subject?
I've just discovered while looking in the IdentityServer3.Core.Extensions.OwinEnvironmentExtensions class, the same extensions class that hosts the GetIdentityServerPartialLoginAsync() method that there is a method named UpdatePartialLoginClaimsAsync(). This method accepts an enumerable of claims so I gave it my new sub claim, but this caused some unknown error (I'm not sure why), but when I gave it all the previous claims with the sub claim replaced everything worked as I wanted too.
var partialLogin = await OwinContext.Environment.GetIdentityServerPartialLoginAsync();
partialLogin.RemoveClaim(identityResult.Identity.FindFirst("sub"));
partialLogin.AddClaim(new Claim("sub", model.NewUsername));
await OwinContext.Environment.UpdatePartialLoginClaimsAsync(partialLogin.Claims);
The code above proved to be my solution.
I've come across an issue when registering new users with my app. The behaviour looks to be by design, but I don't understand why.
My problem is as follows (and I know it's a bit of an edge case):
User browses to my site's login page in two separate tabs in the same browser.
In the first tab, the user logs in and is correctly redirected to my home page.
In the second tab, the user follows my signup logic (which doesn't require any kind of page refresh, it's all done with client side code that culminates in a jQuery AJAX POST to the built in ServiceStack RegistrationService's /register endpoint)
Instead of creating a new user, the second user's details overwrite that of the logged in user's UserAuth record, and the first user can no longer log in.
Looking at the code in ServiceStack.ServiceInterface.Auth.RegistrationService, this behaviour appears to be 100% intentional:
var session = this.GetSession();
var newUserAuth = ToUserAuth(request);
var existingUser = UserAuthRepo.GetUserAuth(session, null);
var registerNewUser = existingUser == null;
var user = registerNewUser
? this.UserAuthRepo.CreateUserAuth(newUserAuth, request.Password)
: this.UserAuthRepo.UpdateUserAuth(existingUser, newUserAuth, request.Password);
Once the first user is logged in, the session cookie for that user gets sent with the registration request, causing the existingUser variable in the code above to be populated with the UserAuth for that user, which is then updated with the registering user details.
Can anyone explain why the code's been written in this way? And is there any way around it without replacing the RegistrationService with my own implementation?
This is the feature that lets you to auto-merge different Auth Providers into the same account in ServiceStack.
I am using ASP.net 3.5 w/ C# using SQL Server with Session State stored in the SQL Server DB.
I have an issue with losing session state across multiple domains, but using the same browser instance and same code base.
For example, We are directing customers to www.MyStore.com to browse our store and we want to send customers to www.MyStore.ShopPlatform.com to checkout w/ secure SSL validation. The session is being re-created when re-directed to www.MyStore.ShopPlatform.com.
The wildcard SSL is installed at www.ShopPlatform.com.
So, The question is.... How do you associate 1 session state cookie to multiple domains (www.MyStore.com and www.MyStore.ShopPlatform.com) on the same server using .net?
If you use cookies for session, you don't. The browser won't send cookies to domains that don't match, and you can't set a cookie for all domains. Even if you could, the session cookie is just a key to server-side session and that key doesn't mean anything without access to the session store. A third party won't have that.
If www.mystore.com and www.mystore.shopplatform.com happen to both be backed by machines you own, and both machines have access to the same session store, then you might be able to use a Cookieless ASP.NET Session config to make it work.
Generally speaking, you can't use session this way.
Since both domains are different, new sessions will always get created.
I suggest using a shared database approach.
Have a column created in users table that can store a random hash. A datatype of uniqueidentifier should do.
When redirecting user, generate a new GUID and store it for the current user and then append the same to the url being redirected. At the receiving domain, setup an endpoint page that will accept an URL encoded path and query string as ReturnUrl parameter and a tokenId parameter for the guid.
Here is a dummy code that will redirect the user to a public endpoint along with a dummy query string parameter. The code was hosted on domain1.local
Using ctx As New DataContexts.SBWebs
Dim u As DataEntities.User = (From usr In ctx.Users Where usr.User.Equals(Page.User.Identity.Name) Select usr).FirstOrDefault
If u Is Nothing Then Exit Sub
Dim id As Guid = Guid.NewGuid
u.Token = id
ctx.SubmitChanges()
Dim newPath As String = "/protected/?tick=" & Now.Ticks
Response.Redirect(String.Format("http://www.domain2.local/EndPoint.aspx?tokenid={0}&ReturnUrl={1}", id.ToString, HttpUtility.UrlEncode(newPath)))
End Using
And the EndPoint.aspx contains the following code..
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Request.QueryString.HasKeys AndAlso Not String.IsNullOrEmpty(Request.QueryString("tokenid")) Then
Using ctx As New DataContexts.SBWebs
Dim usr As DataEntities.User = (From u In ctx.Users Where u.Token.Equals(Request.QueryString("tokenid"))).FirstOrDefault
If usr Is Nothing Then Exit Sub
usr.Token = Nothing
ctx.SubmitChanges()
FormsAuthentication.RedirectFromLoginPage(usr.User, False)
End Using
End If
End Sub
On Security Note: Once the cookie is created, remove the GUID from the table to protect against REPLAY attacks.
EDIT:
Just a word of caution. Don't send user to a ASP.Net protected page (where Deny="?" or something like that is given). Redirect the user to a public end-point that can handle the tokenid and after the setting the cookie, redirect to the intended page.