skip to Main Content

I deployed an application to Azure. Internal users with Windows accounts are logged in automatically when they navigate to the application. External users need to enter their username and password to log into the application. Their username is an email address with a domain that is not that same as the domain used by internal users.

I use HttpContext.Current.User.Identity.Name to set the CreatedBy and ModifiedBy values. I also use @User.Identity.Name in a view to display a greeting. Both of these do not display a value for external users with non-Windows accounts.

What are the alternative options for non-Windows accounts to get these values?

Startup.Auth.cs

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        var clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        var aADInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
        var tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
        var postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
        var authority = string.Format(CultureInfo.InvariantCulture, aADInstance, tenantId);

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies",
            CookieManager = new SystemWebChunkingCookieManager()
        });

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                PostLogoutRedirectUri = postLogoutRedirectUri,
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = ClaimTypes.Upn,
                    RoleClaimType = ClaimTypes.Role
                },
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = context =>
                    {
                        context.HandleResponse();
                        context.Response.Redirect("/");
                        return Task.FromResult(0);
                    }
                }
            }
        );
    }
}

I tried seeing if HttpContext.Current.User.Identity.Name had other options to get the value needed, such as after Identity and after User. I also checked to see if the active directory user profile had any missing values, such as email address or name.

2

Answers


  1. Chosen as BEST ANSWER

    For this question, I updated NameClaimType = ClaimTypes.Upn to NameClaimType = ClaimTypes.Name.

    I first chose Upn instead of Name because Upn seemed more "unique" per their descriptions.

    I confirmed with an external user that the username is now displayed.


  2. In ASP.NET Core, the current user’s identity information can be accessed through the User property on the HttpContext class.

    Whereas the HttpContext.Current property is not available in ASP.NET Core. Instead, you can use dependency injection to get an instance of the IHttpContextAccessor interface and use it to access the current HttpContext.

    public class HomeController : Controller
        {
            private readonly IHttpContextAccessor _contextAccessor;
    
            public HomeController(IHttpContextAccessor contextAccessor)
            {
                _contextAccessor = contextAccessor;
            }
    
            public IActionResult Index()
            {
                var userName = _contextAccessor.HttpContext.User.Identity.Name;
    
                if (string.IsNullOrEmpty(userName) && _contextAccessor.HttpContext.User.Identity.IsAuthenticated)
                {
                    userName = _contextAccessor.HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
                }
    
                return View(userName);
            }
        }
    
    
    1. In the Startup.cs file, configure the authentication in the ConfigureServices method:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.LoginPath = new PathString("/Account/Login");
                options.AccessDeniedPath = new PathString("/Account/AccessDenied");
            });
        
    }
    

    In startup.cs class, in the configure method, use the UseWindowsAuthentication and UseCookieAuthentication for internal and external users.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.Use(async (context, next) =>
        {
            if (context.User.Identity.IsAuthenticated && context.User.Identity.AuthenticationType == "NTLM")
            {
                var email = context.User.Identity.Name;
                if (!email.EndsWith("@internal-domain.com"))
                {
                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                    context.Response.Redirect("/Account/Login");
                    return;
                }
            }
    
            await next();
        });
        app.UseWindowsAuthentication();
        app.UseCookieAuthentication();
      }
    
    

    Create a Login action method that handles the external user login:

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            
            if (IsValidUser(model.Email, model.Password))
            {
                
                if (!model.Email.EndsWith("@internal-domain.com"))
                {
                    var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
                    identity.AddClaim(new Claim(ClaimTypes.Name, model.Email));
                    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", "Invalid UserName.");
                }
            }
            else
            {
                ModelState.AddModelError("", "Invalid password.");
            }
        }
        return View(model);
    }
    
    private bool IsValidUser(string email, string password)
    {
        // check with DB to compare the credentials.
        return true;
    }
    

    I use HttpContext.Current.User.Identity.Name to set the CreatedBy and ModifiedBy values.
    I also use @User.Identity.Name in a view to display a greeting.
    Both of these do not display a value for external users with non-Windows accounts.

    • HttpContext.Current.User.Identity.Name and @User.Identity.Name are used to retrieve the user’s name in an ASP.NET application.
    • These properties are based on the authentication mechanism being used in the application.
    • If the application is using Windows authentication, the User.Identity.Name property will return the user’s Windows login name.
    • If the application is using forms authentication, the User.Identity.Name property will return the username that the user entered when logging in.

    In the view, you can use the following code to check if user is authenticated.

    @if (User.Identity.IsAuthenticated)
    {
        <text>Welcome, @User.Identity.Name</text>
    }
    else
    {
        <text>Welcome, User</text>
    }
    

    Windows Login:

    enter image description here

    enter image description here

    Reference :
    Forms and Windows Authentication
    Thanks @ mvolo for the blog.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search