Search code examples
asp.net-coreasp.net-identityasp.net-core-webapi.net-6.0

How to check if user is logged in to ASP.NET Core web application when using ASP.NET Core Web API to house identity


I have an ASP.NET Core 6 MVC web application where users will create accounts, access a dashboard and retrieve their license key, and an ASP.NET Core 6 Web API. In the Web API, I use the Identity and setup 2 POST methods for Register and Login.

When I test both with Swagger, I can create an account and see it show up in the EF database. I can also run the Login via Swagger and get the success response back that I'm successfully logged in, using PasswordSignInAsync.

On to the fun part, I want the Web API strictly being the only thing to touch the DB. The dbcontext is configured in the API side.

Perhaps I am going about this all wrong, but I made a reference to API from the web app.

In the _layout.cshtml of the web app, I want to hide the login div if the user is authenticated to API. But, it still shows "Login" when I want it to show the "My Profile", "Change Password" and "Logout".

_layout.cshtml:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<APIv2.Models.AccountManagement.ApplicationUserModel> SignInManager
@inject UserManager<APIv2.Models.AccountManagement.ApplicationUserModel> UserManager

<div class="dropdown">
    <a class="dropdown-toggle d-flex align-items-center hidden-arrow"
        href="#"
        id="navbarDropdownMenuAvatar"
        role="button"
        data-mdb-toggle="dropdown"
        aria-expanded="false">
        <i class="fas fa-user-circle fa-xl"></i>
    </a>
    @if (!SignInManager.IsSignedIn(User))
    {
        <ul class="dropdown-menu dropdown-menu-end mt-3"
            aria-labelledby="navbarDropdownMenuAvatar">
            <li>
                <a class="dropdown-item" href="/login">Login</a>
            </li>
        </ul>
     }
     else
     {
         <ul id="account_menu" class="dropdown-menu dropdown-menu-end pt-3"
             aria-labelledby="navbarDropdownMenuAvatar">
             <li>
                 <span class="text-muted ps-3 pt-3">@User.FindFirst("UserFirstName").Value</span>
                 <hr />
             </li>
             <li>
                 <a class="dropdown-item" href="#">My profile</a>
             </li>
             <li>
                 <a class="dropdown-item" href="/changepassword">Change Password</a>
             </li>
             <li>
                 <a class="dropdown-item" href="/logout">Logout</a>
             </li>
         </ul>
      }
</div>

In the web app, the program.cs, I have pointed it to use the dbcontext of API.

program.cs:

builder.Services.AddDbContext<APIv2.Data.ApplicationDbContext>(options =>
    options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<APIv2.Models.AccountManagement.ApplicationUserModel>(options =>
{

}).AddRoles<IdentityRole>()
  .AddEntityFrameworkStores<APIv2.Data.ApplicationDbContext>()
  .AddDefaultTokenProviders();

It's not liking the SignInManager.IsSignedIn(User). I take it that web app cannot see that I am "authenticated" via API since they are 2 separate projects, I guess I just answered my own question.

I do things trial and error and perhaps this a really silly way to do this. Am I better off starting from scratch and starting with ASP.NET Core MVC and add the Web API onto it rather than having 2 separate projects?


Solution

  • The identity is signed-in to a domain. When you do PasswordSignInAsync in api, it generate a cookie in the domain of api. This cookie will make the api part signed. But it doesn't generate cookie in the domain of mvc(since api and mvc are seperate and have different domain), so your mvc part is never signed.
    enter image description here

    So if you want to check sign-in status with SignInManager.IsSignedIn(User),you need to make your mvc signed, too.
    One solution is don't seperate the projects. Make the mvc and api in the same project so they use same domain.
    Another solution is you make a check status endpoint in back-end api. Then use mvc to fetch the status to determine if show login or profile(you need to fetch profile from back-end, too).