locked
I have a problem with returnUrl for authentication RRS feed

  • Question

  • User818337214 posted

    Hi,

    I have a problem with returnUrl for authentication. I used returnUrl in my form 

    <form id="profile-form" method="post" asp-controller="Account" asp-action="UserAccount"
        asp-route-returnUrl="@Html.Raw(Context.Request.Path)" >
    <button class="btn btn-primary" type="submit">Submit</button>
    </form>
    
            [Authorize(Roles = "Admin, User")]
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> UserAccount(AccountModel model, string returnUrl)
            {
                return LocalRedirect(returnUrl);
            }
                services.ConfigureApplicationCookie(options =>
                {
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
                    // Cookie settings
                    options.Cookie.HttpOnly = true;
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    
                    options.LoginPath = "/AccountSystem/UserLogin";
                    //options.ReturnUrlParameter = "returnUrl";
                    options.LogoutPath = "/AccountSystem/UserLogout";
                    options.AccessDeniedPath = "/AccountSystem/UserAccessDenied";
                    options.SlidingExpiration = true;
                });
    public IActionResult UserLogin(string returnUrl)
            {
                int languageId = HttpContext.Session.GetJSon<int>("LanguageId");
    
                var queryArray = returnUrl.Split("returnUrl=");
                if (queryArray.Length == 2)
                {
                    returnUrl = queryArray[1].ToString();
                }
                if (queryArray.Length == 1)
                {
                    returnUrl = queryArray[0].ToString();
                }
    
                var PageAccount = _unitOfWork.Pages.GetAll().Include(i => i.PageRoot).ThenInclude(i => i.Language)
                                            .Where(i => i.IsApproved && i.Language.IsApproved &&
                                                        i.PageRoot.ActionName == "UserLogin" &&
                                                        i.LanguageId == languageId).FirstOrDefault();
    
                return LocalRedirect("~/" + PageAccount.PageRoot.RootName + "/" + PageAccount.Url + "?returnUrl=" + returnUrl);
            }

    when The authentication cookie timeout, I get this url : 

    returnUrl="/Account/UserAccount?returnUrl=%2Fkullanici%2Fhesabim"

    in this url, there is two question mark. I have to get returnUrl in form when that is posted. 

    I figured out it. var queryArray = returnUrl.Split("returnUrl=");

    But there is a problem. why is there two question mark ?

    I tried to change returnUrl with loginReturnUrl

    //options.ReturnUrlParameter = "loginReturnUrl";

    then I get the same result again. 

    how can I change my logic in this structure then I get just one question mark in returnUrl ?

    thank you

    Wednesday, August 14, 2019 11:03 AM

Answers

  • User818337214 posted

    I have to cacth URL in UrlSlugRoute and create newRouteData. if I create action-controller  for this loginpath (options.LoginPath = "/AccountSystem/UserLogin";

    I get this double questionMark. 

    you have to design it in custom route or custom middleware if you use custom route... 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, August 17, 2019 3:46 PM

All replies

  • User475983607 posted

    You are getting two question marks because the caller is sending a string with two question marks. It does not make logical sense that the input parameter "returnVaue" would contain yet another  parameter "returnValue".  I suspect bugs elsewhere in your code or design.

    Please take a few second to run your code through the debugger. 

    Wednesday, August 14, 2019 11:16 AM
  • User753101303 posted

    Hi,

    I don't get the exact behavior you see.

    in this url, there is two question mark

    I see only one or are you talking about %2F which is a / character ? In a controller with a returnUrl parameter /Account/UserAccount?returnUrl=%2Fkullanici%2Fhesabim should show just show the expected value ie /kullanici/hesabim for the returnUrl parameter (it is decoded for you).

    If seeing returnUrl multiple times this is usually caused by a config problem. 

    Wednesday, August 14, 2019 12:04 PM
  • User818337214 posted

    If seeing returnUrl multiple times this is usually caused by a config problem. 

    there is a CultureMiddleware and customRoute. 

    There is no error in Error List. But There is a error in Watch 1.

    Name Value Type
    $exception error CS0103: The name '$exception' does not exist in the current context

    what is it ? How can I see details ? 

    firstly, I try to add try catch in culturemiddleware this error is removed... 

    But I tried to that returnUrl situation, I get this error again but it is working.

    I cant see error detail

    Wednesday, August 14, 2019 4:54 PM
  • User818337214 posted

    Could you explain where is the bug

    using ECommerce.Repository.Abstract;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Localization;
    using Microsoft.AspNetCore.Routing;
    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace ECommerce.WebUI.Infrastructure
    {
        public class UrlSlugRoute : IRouter
        {
            private readonly IRouter _target;
    
            public UrlSlugRoute(IRouter target)
            {
                _target = target;
            }
    
            public async Task RouteAsync(RouteContext context)
            {
                //https://github.com/simplcommerce/SimplCommerce/blob/master/src/Modules/SimplCommerce.Module.Core/Extensions/UrlSlugRoute.cs
                var requestPath = context.HttpContext.Request.Path.Value;
                if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
                {
                    // Trim the leading slash
                    requestPath = requestPath.Substring(1);
                }
                var unitOfWork = (IUnitOfWork)context.HttpContext.RequestServices.GetService(typeof(IUnitOfWork));
                var segments = requestPath.Split('/');
                var url = segments[0].ToLower();
                if (segments.Length == 2)
                {
                    url = segments[1].ToLower();
                }
                var page = unitOfWork.Pages.GetAll().Include(i => i.PageRoot).ThenInclude(i => i.Language)
                                                        .Where(i => i.IsApproved && i.Language.IsApproved &&
                                                                    i.Url.ToLower() == url).FirstOrDefault();
                // Invoke MVC controller/action
                var oldRouteData = context.RouteData;
                var newRouteData = new RouteData(oldRouteData);
                newRouteData.Routers.Add(_target);
    
                // If we got back a null value set, that means the URI did not match)
                if (page == null)
                {
                    return;
                }
    
                if (url == "")
                {
                    newRouteData.Values["controller"] = "Home";
                    newRouteData.Values["action"] = "Index";
                }
                else
                {
                    //newRouteData.Values["area"] = urlSlug.EntityType.AreaName;
                    newRouteData.Values["controller"] = page.PageRoot.ControllerName;
                    newRouteData.Values["action"] = page.PageRoot.ActionName;
                    newRouteData.Values["pageId"] = page.LanguageId;
                    
                }
    
                int languageId = context.HttpContext.Session.GetJSon<int>("LanguageId");
                if (languageId != page.LanguageId)
                {
                    int currenyId = unitOfWork.Languages.GetAll().Where(i => i.LanguageId == page.LanguageId).FirstOrDefault().CurrencyId;
    
                    //SET CULTURE
                    var culture = new CultureInfo(page.Language.Culture);
                    CultureInfo.CurrentCulture = culture;
                    CultureInfo.CurrentUICulture = culture;
                    //SET SESSION
                    context.HttpContext.Session.SetJson("LanguageId", page.LanguageId);
                    context.HttpContext.Session.SetJson("Culture", page.Language.Culture);
                    context.HttpContext.Session.SetJson("SettingLanguageId", page.LanguageId);
                    //SET COOKIE CULTURE 
                    context.HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName,
                        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(page.Language.Culture)),
                        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });
                }
    
                context.RouteData = newRouteData;
                await _target.RouteAsync(context);
            }
    
    
            public VirtualPathData GetVirtualPath(VirtualPathContext context)
            {
                return null;
            }
        }
    }
    

    Wednesday, August 14, 2019 8:44 PM
  • User711641945 posted

    Hi suat_suphi,

    suat_suphi

    in this url, there is two question mark.

    First,I have not seen two question mark in the url. What did you want to mean?

    Secondly,Could you share what is your current url and what is your expected url?

    At last, could you share a simple demo that could reproduce your issue?

    Best Regards,

    Rena

    Thursday, August 15, 2019 9:11 AM
  • User818337214 posted

    First,I have not seen two question mark in the url. What did you want to mean?

    Secondly,Could you share what is your current url and what is your expected url?

    At last, could you share a simple demo that could reproduce your issue?

    there is two question mark if you

    when The authentication cookie timeout, I get this url : 

    https://localhost:44382/kullanici/oturum-ac?returnUrl=/Account/UserAccount?returnUrl=%2Fkullanici%2Fhesabim 

    If seeing returnUrl multiple times this is usually caused by a config problem

    problem is here : 

    var newRouteData = new RouteData(oldRouteData); 

    Please take a few second to run your code through the debugger. 

    there is no error anywhere 

    Thursday, August 15, 2019 9:54 AM
  • User475983607 posted

    there is no error anywhere 

    The code has a logical error - a bug - that is generating an invalid URL.

    https://localhost:44382/kullanici/oturum-ac?returnUrl=/Account/UserAccount?returnUrl=%2Fkullanici%2Fhesabim 

    I would expect the URL to have the following format.

    https://localhost:44382/kullanici/oturum-ac?returnUrl=%2Fkullanici%2Fhesabim

    Use the Visual Studio to single step through your code.

    Thursday, August 15, 2019 10:37 AM
  • User818337214 posted

    Use the Visual Studio to single step through your code.

    could you try with custom route ? do you wanna create to you. I shared a urlslugroute. 

    /user/my-account <- slug url 

    /Account/UserAccount <- real control and action 

    if the page is in slug url and the authentication cookie is in timeout, you will get this result. there is two question mark in the url 

    Thursday, August 15, 2019 1:54 PM
  • User818337214 posted

    if the page is in slug url when the authentication cookie is in timeout or delete cookie and click submit button,

    you will get this result. there is two question mark in the url 

    download

    just change connectionstring

    "DefaultConnection": "Server=.;Database=SlugUrl;User Id=sa;Password=Password1*;",

    login -> click "user page" 

    Thursday, August 15, 2019 2:45 PM
  • User818337214 posted

    I have to cacth URL in UrlSlugRoute and create newRouteData. if I create action-controller  for this loginpath (options.LoginPath = "/AccountSystem/UserLogin";

    I get this double questionMark. 

    you have to design it in custom route or custom middleware if you use custom route... 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, August 17, 2019 3:46 PM