InvalidOperationException: Cannot provide a value for property 'AuthStateProv'

Posted 15 days ago by Online_Skeleton
0

Good afternoon. I have set up some code for authenticating users with a freeIPA server,but whenever I attempt to access the login page,I get an error that the property value cannot be provided. It looks like I'm doing everything right in terms of declarations. I have attatched the relevant code below. 
Here is my custom auth state implementation,my loginmodel for handling the freeIPA end,my .razor page for handling the logins,my Program.cs and my App.razor

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using CIFInventory.Pages;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
using System.Security.Claims;
namespace CIFInventory.Auth
{
    public class AuthStateProv : AuthenticationStateProvider //Deals with login states so people can't just access any page without logging in
    {
        private NavigationManager nav_man; 
        private bool loggedIn;

        public AuthStateProv(NavigationManager navigationManager)
        { //Dependency injection

            nav_man = navigationManager;

        }

        public void SetLoginStatus(bool isloggedin)
        {
            loggedIn = isloggedin;
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());

        }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            ClaimsPrincipal user;

            if (loggedIn)
            {
                // Create claims for the authenticated user
                var claims = new[]
                {
                new Claim(ClaimTypes.Name, "AuthenticatedUser"),
                // Add more claims as needed
            };
                user = new ClaimsPrincipal(new ClaimsIdentity(claims, "CustomAuth"));
            }
            else
            {
                user = new ClaimsPrincipal(new ClaimsIdentity());
            }

            return await Task.FromResult(new AuthenticationState(user));
        }

    }
}


Here is my LoginModel for handling the FreeIPA end of things.

using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using FreeIPA.DotNet;
using FreeIPA.DotNet.Models.Login;
namespace CIFInventory.Models
{
    public class LoginModel //Handles the IPA end of things
    {
        [Required(ErrorMessage = "Username is required.")]
        public string mod_Username { get; set; }

        [Required(ErrorMessage = "Password is required.")]
        public string mod_Password { get; set; }

        public event Action<LoginModel> OnSubmit;
        public async Task<bool> Submit()
        {
            if (OnSubmit != null)
            {

                string URL = "loginurl";
                var ipaClient = new IpaClient(URL);

                var login = await ipaClient.LoginWithPassword(new IpaLoginRequestModel
                {
                    Username = mod_Username,
                    Password = mod_Password

                });
                if (login.Success)
                {
                    //Console.WriteLine(mod_Username);
                    //Console.WriteLine(mod_Password);
                    Console.WriteLine("Sucessful login!");

                    return true;
                }
                else
                {
                    var ErrorMessage = login.Data.Message;
                    Console.WriteLine($"Login failed: {ErrorMessage}");
                    return false;
                }
                OnSubmit(this);

                

            }
            return false; //This happens if null
        }
    }
}
@page "/login"
@using CIFInventory.Models
@using System.ComponentModel.DataAnnotations
@using CIFInventory.Auth
@inject AuthStateProv AuthStateProv
<h3>Login</h3>
<div class="row">
    <div class="col-md-6">
        <EditForm Model="@loginModel" OnValidSubmit="@HandleValidSubmit">
            <DataAnnotationsValidator />
            <ValidationSummary />
            <div class="form-group">
                <label for="username">Username:</label>
                <InputText id="username" class="form-control" @bind-Value="@loginModel.mod_Username" />
                <ValidationMessage For="@(() => loginModel.mod_Username)" />
            </div>

            <div class="form-group">
                <label for="password">Password:</label>
                <InputText type="password" id="password" class="form-control" @bind-Value="@loginModel.mod_Password" />
                <ValidationMessage For="@(() => loginModel.mod_Password)" />
            </div>

            <button type="submit" class="btn btn-primary">Login</button>
        </EditForm>
    </div>
</div>


@code {
    private LoginModel loginModel;
    public bool status;
    protected override void OnInitialized()
    {
        loginModel = new LoginModel();
        
    }

    public async Task HandleValidSubmit()
    {
        status = await loginModel.Submit();
        AuthStateProv.SetLoginStatus(status);
        
    }

    
}










Above is my .razor page for login handling and below is my Program.cs

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using CIFInventory.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Components.Authorization;
using CIFInventory.Auth;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorizationCore();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
//builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddScoped<AuthenticationStateProvider, AuthStateProv>();

builder.Services.AddDbContext<InventoryContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("InventoryDatabase")));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

And finally,here is my App.razor
 

<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
<p>Authorizing...</p>
</Authorizing>
<NotAuthorized>
<Redirect To="/login" />
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>




Thanks for your time!

  • 0

    I didn't test any of this, but try casting your custom authentication state provider in the razor file, something like 

    ((AuthenticationStateProvider)AuthStateProv).SetLoginStatus(status);
    Posted 10 days ago by selliott Edited 10 days ago
Someone is typing...

Post a Reply

You must be logged in to add a new post.
Number of online users: 0
An error has occurred. This application may no longer respond until reloaded. Reload 🗙