HttpContext.Current.User.Identity.IsAuthenticated 将 okta openidconnect 与 .net 核心项目集成时导致无限重定向循环

HttpContext.Current.User.Identity.IsAuthenticated results in infinite redirect loop when integrating okta openidconnect with .net core project

这里是 startup.cs 我已经按照以下配置了 okta openid connect。请审核

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)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();
        services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOktaMvc(new OktaMvcOptions
            {
                // Replace these values with your Okta configuration
                OktaDomain = Configuration.GetValue<string>("AppSettings:OktaDomain"),
                ClientId = Configuration.GetValue<string>("AppSettings:ClientId"),
                ClientSecret = Configuration.GetValue<string>("AppSettings:ClientSecret"),
                Scope = new List<string> { "openid", "profile", "email" },
            });

        //services.AddAuthorization();


        services.Configure<FormOptions>(x => x.ValueCountLimit = 8192);

        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => false;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        services.AddOptions();

        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));


        var lockoutOptions = new LockoutOptions()
        {
            AllowedForNewUsers = true,
            DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5),
            MaxFailedAccessAttempts = 3
        };

        services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(options =>
            {
                options.Password.RequireDigit = true;
                options.Password.RequiredLength = 6;
                options.Password.RequiredUniqueChars = 0;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Lockout = lockoutOptions;
            })
            .AddEntityFrameworkStores<AmpCoreContext>().AddDefaultTokenProviders();

        services.ConfigureApplicationCookie(options =>
        {
            //     Cookie settings
            options.Cookie.HttpOnly = true;
            options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
            options.LoginPath = new PathString("/Identity/Account/Login");
            options.AccessDeniedPath = "/Identity/Account/AccessDenied";
            options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
            options.SlidingExpiration = true;
        });
        services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(20); });


        services
            .AddControllersWithViews()
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            // Maintain property names during serialization. See:
            // https://github.com/aspnet/Announcements/issues/194
            .AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

        services.AddRazorPages().AddRazorRuntimeCompilation();

        services.AddHttpContextAccessor();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        var culture = CultureInfo.CreateSpecificCulture("en-US");
        var dateformat = new DateTimeFormatInfo
        {
            ShortDatePattern = "MM/dd/yyyy",
            LongDatePattern = "MM/dd/yyyy hh:mm:ss tt"
        };
        culture.DateTimeFormat = dateformat;

        var supportedCultures = new[] { culture };

        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture(culture),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        });
        using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            try
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<AmpCoreContext>();
                var customers = context.Customer.ToListAsync().Result;
                string output =
                    Newtonsoft.Json.JsonConvert.SerializeObject(customers, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText("tenants.json", output);
            }
            catch (Exception)
            {
                throw;
            }
        }

        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.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        //app.UseCookiePolicy();
        app.UseSession();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");

            endpoints.MapRazorPages();
        });
    }
}

这是我的帐户控制器,在登录按钮上单击我将其重定向到帐户控制器 singin 方法。但它总是在循环中调用。请检查下面的代码

public class AccountController : Controller
{
    public IActionResult SignIn()
    {
        if (!HttpContext.User.Identity.IsAuthenticated)
        {
            return Challenge(OktaDefaults.MvcAuthenticationScheme);
        }

        return RedirectToAction("Index", "Home");
    }

    [HttpPost]
    public IActionResult SignOut()
    {
        return new SignOutResult(
            new[]
            {
                OktaDefaults.MvcAuthenticationScheme,
                CookieAuthenticationDefaults.AuthenticationScheme,
            },
            new AuthenticationProperties { RedirectUri = "/Home/" });
    }
}

它重定向到 okta,okta return 但是 HttpContext.User.Identity.IsAuthenticated 在帐户控制器中总是错误的,它是无限循环。

这是家庭控制器

using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using Project.Common;
using System;
using Microsoft.AspNetCore.Identity;
using Project.Data.Identity;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
using Microsoft.AspNetCore.DataProtection;
using Project.Application.Interfaces;
using Project.Application.ViewModel;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Data;
using Microsoft.AspNetCore.Http;
using Project.Data.Data;
using ErrorViewModel = Project.Models.ErrorViewModel;
using System.Linq;
using Okta.AspNetCore;
using Microsoft.AspNetCore.Authorization;

namespace Project.Controllers
{
    [Authorize]
    public class HomeController : BaseController
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly ICustomerService _customerService;
        private IPasswordHasher<ApplicationUser> _passwordHasher;
        private readonly IFieldService _fieldService;
        private IModuleService _moduleService;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private ISession _session => _httpContextAccessor.HttpContext.Session;
        private readonly IUserAccessSecurityService _userAccessSecurityService;
        private readonly IGroupService _groupService;
        private readonly Context _context;
        private IDataProtectionProvider _provider;
        private readonly IUserSessionLogService _userSessionLogService;
        public HomeController(UserManager<ApplicationUser> userManager, ICustomerService customerService, IPasswordHasher<ApplicationUser> passwordHasher, IFieldService fieldService,
            IModuleService moduleService, IUserAccessSecurityService userAccessSecurityService, IGroupService groupService, Context context, IHttpContextAccessor httpContextAccessor,
            IDataProtectionProvider provider, SignInManager<ApplicationUser> signInManager, IUserSessionLogService userSessionLogService) : base(signInManager, userAccessSecurityService, provider, userSessionLogService)
        {
            _userManager = userManager;
            _customerService = customerService;
            _passwordHasher = passwordHasher;
            _fieldService = fieldService;
            _moduleService = moduleService;
            _userAccessSecurityService = userAccessSecurityService;
            _groupService = groupService;
            _context = context;
            _httpContextAccessor = httpContextAccessor;
            _provider = provider;
            _userSessionLogService = userSessionLogService;
        }
        public IActionResult unauthorised()
        {
            return View("~/Views/Home/AccessDenied.cshtml");
        }
        [Authorize]
        public IActionResult Index()
        {
            if (HttpContext.Session.GetObjectFromJson<Guid>("CurrentUserId") != Guid.Empty)
            {
                var Fk_Customer = HttpContext.Session.GetObjectFromJson<int>("CurrentCustomer");
                var FK_User = HttpContext.Session.GetObjectFromJson<Guid>("CurrentUserId");
                bool hasGroup = false;

                DashBoardViewModel dashBoardViewModel = new DashBoardViewModel();
                List<ViewUserGroup> viewUserGroup = new List<ViewUserGroup>();
                ApplicationUser appUsers = _context.Users.SingleOrDefault(x => x.Id == FK_User);
                bool isSuperAdmin = _context.UserType.Where(x => x.ID == appUsers.FK_UserType && x.Type.ToLower() == "super admin").Any();

                bool isAdmin = _context.UserType.Where(x => x.ID == appUsers.FK_UserType && x.Type.ToLower() == "company admin").Any();

                viewUserGroup = _userAccessSecurityService.GetUserGroupByUser(Fk_Customer, FK_User);

                if (viewUserGroup.Count > 0)
                {
                    if (viewUserGroup[0].Fk_Group != 0 && viewUserGroup[0].PK_Group != 0)
                        hasGroup = true;
                }
                ViewBag.hasGroup = hasGroup;
                ViewBag.isSuperAdmin = isSuperAdmin;

                DataTable dtPendingAssetCount = _fieldService.GetPendingAssetCount(Convert.ToInt32(Fk_Customer), (isAdmin ? true : (isSuperAdmin) ? true : false), FK_User);
                if (dtPendingAssetCount != null && dtPendingAssetCount.Rows.Count > 0)
                {
                    dashBoardViewModel.AccountReminder.Pending_Valuation_Count = dtPendingAssetCount.Rows[0]["Pending_Valuation_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_Valuation_Count"]) : 0;
                    dashBoardViewModel.AccountReminder.Pending_New_Assets_Count = dtPendingAssetCount.Rows[0]["Pending_New_Assets_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_New_Assets_Count"]) : 0;
                    dashBoardViewModel.AccountReminder.Pending_Change_Request_Count = dtPendingAssetCount.Rows[0]["Pending_Change_Request_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_Change_Request_Count"]) : 0;
                    dashBoardViewModel.AccountReminder.Pending_New_Assets_State_Count = dtPendingAssetCount.Rows[0]["Pending_New_Assets_State_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_New_Assets_State_Count"]) : 0;
                    dashBoardViewModel.AccountReminder.Pending_Change_Request_State_Count = dtPendingAssetCount.Rows[0]["Pending_Change_Request_State_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_Change_Request_State_Count"]) : 0;
                    dashBoardViewModel.AccountReminder.Pending_Valuation_State_Count = dtPendingAssetCount.Rows[0]["Pending_Valuation_State_Count"] != DBNull.Value ? Convert.ToInt32(dtPendingAssetCount.Rows[0]["Pending_Valuation_State_Count"]) : 0;
                }

                dashBoardViewModel.AccountReminder.New_Asset_Pending_State = _context.LookUp.Where(x => x.Field_Name.ToLower() == ConstantStrings.State_Of_Asset.ToLower() && x.Value.ToLower() == State_Of_Asset.New_Asset_Pending.ToLower() && x.FK_Customer == Fk_Customer && !x.Is_Deleted).Select(x => x.PK_LookUp).FirstOrDefault();
                dashBoardViewModel.AccountReminder.Pending_Change_Request_State = _context.LookUp.Where(x => x.Field_Name.ToLower() == ConstantStrings.State_Of_Asset.ToLower() && x.Value.ToLower() == State_Of_Asset.Change_request_Pending.ToLower() && x.FK_Customer == Fk_Customer && !x.Is_Deleted).Select(x => x.PK_LookUp).FirstOrDefault();
                dashBoardViewModel.AccountReminder.Pending_Valuation_State = _context.LookUp.Where(x => x.Field_Name.ToLower() == ConstantStrings.State_Of_Asset.ToLower() && x.Value.ToLower() == State_Of_Asset.Valuation_Pending.ToLower() && x.FK_Customer == Fk_Customer && !x.Is_Deleted).Select(x => x.PK_LookUp).FirstOrDefault();


                dashBoardViewModel.PropertyRisk = _fieldService.GetNumberOfLocationDetails(Fk_Customer);
                return View(dashBoardViewModel);
            }
            else
            {
                return LocalRedirect("~/Identity/Account/Login");
            }
        }
        [HttpGet]
        public async Task<IActionResult> AccountSettings()
        {
            if (HttpContext.Session.GetObjectFromJson<Guid>("CurrentUserId") != Guid.Empty)
            {
                var currentUser = await _userManager.GetUserAsync(HttpContext.User);
                var user = await _userManager.FindByNameAsync(currentUser.UserName);

                AccountSettings model = new AccountSettings();
                List<SelectListItem> List = _customerService.GetCustomerReminderQuestions();
                model.Reminder_Question_List = List;
                model.Email = Convert.ToString(user.Email);
                return View(model);
            }
            else
            {
                return LocalRedirect("~/Identity/Account/Login");
            }
        }
        [HttpPost]
        public async Task<IActionResult> AccountSettings(AccountSettings Account_Setting_Data)
        {
            var currentUser = await _userManager.GetUserAsync(HttpContext.User);
            var user = await _userManager.FindByNameAsync(currentUser.UserName);
            bool Result = false;
            if (user != null)
            {
                if (!string.IsNullOrEmpty(Account_Setting_Data.Email) && !string.IsNullOrEmpty(Account_Setting_Data.Password))
                {
                    user.Email = Account_Setting_Data.Email;
                    user.PasswordHash = _passwordHasher.HashPassword(user, Account_Setting_Data.Password);
                    user.FK_Reminder_Question = Account_Setting_Data.Reminder_Question == null ? user.FK_Reminder_Question : Convert.ToInt32(Account_Setting_Data.Reminder_Question);
                    user.Answer = Account_Setting_Data.Answer == null ? user.Answer : Account_Setting_Data.Answer;
                    var identity = await _userManager.UpdateAsync(user);
                    if (identity.Succeeded)
                        Result = true;
                }
            }
            return Json(Result);
        }
       
        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }

        

    }
}


这里是homecontroller继承的basecontroller

using Project.Application.Entities;
using Project.Application.Interfaces;
using Project.Application.ViewModel;
using Project.Common;
using Project.Data.Data;
using Project.Data.Identity;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Project.Controllers
{
    [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public class BaseController : Controller
    {
        //private readonly ApplicationSignInManager _signInManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly IUserAccessSecurityService _userAccessSecurityService;
        private readonly IDataProtector _protector;
        private readonly IUserSessionLogService _userSessionLogService;
        //public BaseController(ApplicationSignInManager signInManager)
        public BaseController(SignInManager<ApplicationUser> signInManager, IUserAccessSecurityService userAccessSecurityService, IDataProtectionProvider provider, IUserSessionLogService userSessionLogService)
        {
            _signInManager = signInManager;
            _userAccessSecurityService = userAccessSecurityService;
            _protector = provider.CreateProtector("Protector");
            _userSessionLogService = userSessionLogService;
        }
         
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (HttpContext.Session.GetObjectFromJson<Guid>("CurrentUserId") == Guid.Empty)
            {
                _signInManager.SignOutAsync();
                bool isAjaxCall = context.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest";
                if(isAjaxCall)
                {
                    context.Result = new UnauthorizedResult();
                }
                else
                {
                    var PK_ID = TempData["UserLogId"];
                    if (Convert.ToInt32(PK_ID) > 0)
                        _userSessionLogService.InsertUpdateSession(0, Convert.ToInt32(PK_ID), "", "", new Guid());
                    context.Result = new RedirectResult("~/Identity/Account/Login");
                }
                return;
            }
            else
            {
                TempData["UserLogId"] = HttpContext.Session.GetObjectFromJson<int>("SessionId");
            }

            if (!HttpContext.Session.GetObjectFromJson<bool>("IsAdmin") && !string.IsNullOrEmpty(context.HttpContext.Request.Query["q"].ToString()))
            {
                //&& context.HttpContext.Request.QueryString.Value!=null && context.HttpContext.Request.QueryString.Value!=""
                var currentUserId = HttpContext.Session.GetObjectFromJson<Guid>("CurrentUserId");
                int CustomerId = HttpContext.Session.GetObjectFromJson<int>("CurrentCustomer");

                var qs = context.HttpContext.Request.Query["q"].ToString();//context.HttpContext.Request.QueryString.Value; //HttpContext.Request.Query["q"];
                var queryString = _protector.Unprotect(qs);
                var parameters = ClsGeneral.GetParams(queryString);
                var pageId = 0;
                var tableName = "";

                if (parameters.TryGetValue("PageId", out string value))
                {
                    pageId = Convert.ToInt32(value);
                }
                if (parameters.TryGetValue("TableName", out value))
                {
                    tableName = Convert.ToString(value);
                }


                List<GroupPagesRights> view_Group_Page_Rights = _userAccessSecurityService.GetGroupPagesRightsByUser(CustomerId, currentUserId);
                if (view_Group_Page_Rights == null || view_Group_Page_Rights.Count == 0 || (!view_Group_Page_Rights.Any(x => x.FK_Page == pageId)))
                {
                    context.HttpContext.Response.Redirect(Url.Action("Unauthorised", "Home"));
                }
               
            }
            
            base.OnActionExecuting(context);
        }
    }
}

请帮忙

谢谢

如果您在操作或 class 上没有 [Authorize],或者没有对用户进行身份验证的后备身份验证策略,则不会对用户进行身份验证。

我们可以在 SignIn 上加上 [Authorize],但这会破坏目的。

您还有另一种选择,手动验证并检查是否成功:

[HttpGet]
public async Task<ActionResult> SignIn()
{
    var oktaResult = await HttpContext.AuthenticateAsync(OktaDefaults.MvcAuthenticationScheme);
    if (oktaResult.Succeeded)
    {
        return RedirectToAction("Index", "Home");
    }
    
    return Challenge(OktaDefaults.MvcAuthenticationScheme);
}