Click here to Skip to main content
15,885,216 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Scenario:

I'm implementing asp.net core 3.1 MVC project. I authorize my user via ldap Active Directory service. The user authenticates successfully and enter into my website. but after clicking on each menu item in order to see the related controller index it shows white page. I wrote on top of all my controller class [Authorize] keyword in order to let any authorized user to see all controllers.

My Problem is when user clicks on each menu item in home in order to see the related controller's index, it shows white page and when I publish my project on ldap server, it shows me 404 error. I appreciate if any one can suggest me a solution. It seems to me the routing has problem but I'm not sure. in my menu there are items for Home index controller, Application index controller, ApiApplication index controller and Gate index controller and although on top of Home controller like the others I wrote [Authorize] keyword, if the user click on its menu item, it doesn't show white page and it works correctly but the others show white page. I even wrote on top of my controller classes the keyword [AllowAnonymous] but still I see white pages for index pages for each controller. Should I add anything to startup.cs for AutheticationHelper or CustomAuthenticationMiddleware as a service?

What I have tried:

Here is my code:
C#
namespace CSDDashboard.Controllers
{
    [Route("[controller]/[action]")]
    [AllowAnonymous]
    public class AccountController : Controller
    {
        private readonly LdapUserManager _userManager;
        private readonly LdapSignInManager _signInManager;
        private readonly ILogger _logger;

        public AccountController(
            LdapUserManager userManager,
            LdapSignInManager signInManager,
            ILogger<accountcontroller> logger)
        {
            this._userManager = userManager;
            this._signInManager = signInManager;
            this._logger = logger;
        }

        [AllowAnonymous]
        [HttpGet]
        public async Task<IActionResult> Signin(string returnUrl = null)
        {
            // Clear the existing external cookie to ensure a clean login process
            await this.HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

            this.ViewData["ReturnUrl"] = returnUrl;

            return this.View();
        }

        [AllowAnonymous]
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Signin(SigninViewModel model, string returnUrl = null)
        {
            this.ViewData["ReturnUrl"] = returnUrl;

            using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "tehran.iri"))
            {
                // validate the user's credentials
                //var result = ctx.ValidateCredentials(model.UserName, model.Password);
                //    try { 
                if (ctx.ValidateCredentials(model.UserName, model.Password))
                {
                    // credentials are OK --> allow user in
                    HttpContext.Session.MarkAsAuthenticated(model.UserName);
                    return RedirectToLocal(returnUrl);

                }
                else
                {
                    this.TempData["ErrorMessage"] = "The username and/or password are incorrect!";

                    return this.View(model);
                    // credentials aren't OK --> send back error message
                }
            }
        }
    }
}
C#
public static class AuthenticationHelper
{
    private const string SessionKey = "AuthenticationHelper.UserName";

    public static void MarkAsAuthenticated(this Microsoft.AspNetCore.Http.ISession session, string authenticatedUserName)
    {
        session.SetString(SessionKey, authenticatedUserName);
    }

    public static ClaimsPrincipal GetAuthenticatedUser(this Microsoft.AspNetCore.Http.ISession session)
    {
        string authenticatedUserName = session.GetString(SessionKey);
        if (string.IsNullOrEmpty(authenticatedUserName)) return null;
        return new GenericPrincipal(new GenericIdentity(authenticatedUserName), Array.Empty<string>());
    }
}

public class CustomAuthenticationMiddleware
{
    private readonly RequestDelegate _next;

    public CustomAuthenticationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        ClaimsPrincipal user = context.Session.GetAuthenticatedUser();
        if (user != null) context.User = user;
        await _next(context);
    }
}

public static class CustomAuthenticationMiddlewareExtensions
{
    public static IApplicationBuilder UseCustomAuthentication(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<customauthenticationmiddleware>();
    }
}
C#
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<ldapsettings>(Configuration.GetSection("LdapSettings"));
        services.AddDbContext<ldapdbcontext>(options =>
            options.UseSqlite(
                Configuration.GetConnectionString("CSDDashboardContext")));

        //-------------------------------------------------
        services.AddIdentity<ldapuser, identityrole="">()
            .AddEntityFrameworkStores<ldapdbcontext>()
            .AddUserManager<ldapusermanager>()
            .AddSignInManager<ldapsigninmanager>()
            .AddDefaultTokenProviders();

        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.Name = "CSDDashboard";
            options.LoginPath = "/Account/Signin"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login
            options.LogoutPath = "/Account/Signout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout
            options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath is not set here, ASP.NET Core will default to /Account/AccessDenied
            options.SlidingExpiration = true;
            options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
        });

        services.AddRazorPages();

        services.AddTransient<ILdapService, ldapservice="">();

        //-------------------------------------------------

        services.AddControllersWithViews();

        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromMinutes(30);//We set Time here 
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });

        services.AddDistributedMemoryCache();

        //Notice this is NOT the same class... Assuming this is a valid DBContext.  You need to add this class as well.
        services.AddDbContext<CssdDashboardContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("CSDDashboardContext")));

        services.AddDbContext<CsdDashboardContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("CSDDashboardContext")));

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/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.UseSession();

        app.UseRouting();
        app.UseCustomAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
               // Here are all of my controllers, but as it seems just I can uncomment one controller pattern here, I commented all the others
               // pattern: "{controller=Applications}/{action=Index}/{id?}");
               // pattern: "{controller=Home}/{action=Index}/{id?}");
               // pattern: "{controller=ApiApplications}/{action=Index}/{id?}");
               pattern: "{controller=Gates}/{action=Index}/{id?}");
        });
    }
}
Posted
Updated 7-May-20 5:54am
v4
Comments
Richard Deeming 7-May-20 11:58am    
NB: You don't need to list all of your controllers in the MapControllerRoute call. You're defining a pattern for the route, and the values after = are just the default values.

pattern: "{controller=Home}/{action=Index}/{id?}"

will match:
* /AnyController/AnyAction/AnyId
* /AnyController/AnyAction
* /AnyController (defaults to the Index action on that controller)
* / (defaults to the Index action on the HomeController)

Routing to controller actions in ASP.NET Core | Microsoft Docs[^]

1 solution

404 is the error "resource not found".

Sounds like you requested resource cant be found. Reason may be missing rights, illformated or incomplete path strings.

Tip: use UNC pathes
 
Share this answer
 
Comments
ElenaRez 2-May-20 10:13am    
Thank you for your reply. Could you please explain how can I use UNC paths?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900